Setup

Create directory structure and clone repo

(Working directory on EBI cluster: /hps/research1/birney/users/ian/mikk_paper)

# move to working directory
cd /your/working/directory
# clone git repository
git clone https://github.com/Ian-Brettell/mikk_genome.git

Create conda evironment

conda env create \
  -n mikk_env \
  -f mikk_genome/code/config/conda_env.yml
  
conda activate mikk_env

Setup R

# Load required libraries
require(here)
source(here::here("code", "scripts", "ld_decay", "source.R"))

Copy MIKK panel VCF into working directory

(See supplementary material for how VCF was generated.)

# create directory for VCFs
mkdir vcfs

# Copy into working directory
cp /nfs/research1/birney/projects/medaka/inbred_panel/medaka-alignments-release-94/vcf/medaka_inbred_panel_ensembl_new_reference_release_94.vcf* vcfs

Key-value file for cram ID to line ID

mikk_genome/data/20200206_cram_id_to_line_id.txt

Remove sibling lines and replicates

Full list of 80 extant MIKK panel lines: mikk_genome/data/20200210_panel_lines_full.txt

Note: Line 130-2 is missing from the MIKK panel VCF.

Identify sibling lines

cat mikk_genome/data/20200210_panel_lines_full.txt | cut -f1 -d"-" | sort | uniq -d
  • 106
  • 11
  • 117
  • 131
  • 132
  • 135
  • 14
  • 140
  • 23
  • 39
  • 4
  • 40
  • 59
  • 69
  • 72
  • 80

Only keep first sibling line ( suffix _1); manually remove all others and write list of non-sibling lines to here: mikk_genome/data/20200227_panel_lines_no-sibs.txt. 64 lines total.

Excluded sibling lines here: mikk_genome/data/20200227_panel_lines_excluded.txt. 16 lines total.

Replace all dashes with underscores to match mikk_genome/data/20200206_cram_id_to_line_id.txt key file

sed 's/-/_/g' mikk_genome/data/20200227_panel_lines_no-sibs.txt \
  > mikk_genome/data/20200227_panel_lines_no-sibs_us.txt

Extract the lines to keep from the key file.

awk  'FNR==NR {f1[$0]; next} $2 in f1' \
  mikk_genome/data/20200227_panel_lines_no-sibs_us.txt \
  mikk_genome/data/20200206_cram_id_to_line_id.txt \
    > mikk_genome/data/20200227_cram2line_no-sibs.txt

Has 66 lines instead of 63 (64 lines minus 130-2, which isn’t in the VCF), so there must be replicates Find out which ones:

cat mikk_genome/data/20200227_cram2line_no-sibs.txt | cut -f2 | cut -f1 -d"_" | sort | uniq -d

32 71 84

Manually removed duplicate lines (mikk_genome/data/20200227_duplicates_excluded.txt):

  • 24271_7#5 32_2
  • 24271_8#4 71_1
  • 24259_1#1 84_2

Final no-sibling-lines CRAM-to-lineID key file: mikk_genome/data/20200227_cram2line_no-sibs.txt

Create MIKK panel VCF with no sibling lines

# create no-sibs file with CRAM ID only
cut -f1 mikk_genome/data/20200227_cram2line_no-sibs.txt \
  > mikk_genome/data/20200227_cram2line_no-sibs_cram-only.txt
  
# make new VCF having filtered out non-MIKK and sibling lines
bcftools view \
  --output-file vcfs/panel_no-sibs.vcf \
  --samples-file mikk_genome/data/20200227_cram2line_no-sibs_cram-only.txt \
  vcfs/medaka_inbred_panel_ensembl_new_reference_release_94.vcf
  
# recode with line IDs
bcftools reheader \
  --output vcfs/panel_no-sibs_line-ids.vcf \
  --samples mikk_genome/data/20200227_cram2line_no-sibs.txt \
  vcfs/panel_no-sibs.vcf
  
# compress
bcftools view \
  --output-type z \
  --output-file vcfs/panel_no-sibs_line-ids.vcf.gz \
  vcfs/panel_no-sibs_line-ids.vcf
  
# index
bcftools index \
  --tbi \
  vcfs/panel_no-sibs_line-ids.vcf.gz

# get stats
mkdir stats

bcftools stats \
  vcfs/panel_no-sibs_line-ids.vcf.gz \
  > stats/20200305_panel_no-sibs.txt

## get basic counts
grep "^SN" stats/20200305_panel_no-sibs.txt

Make a version with no missing variants

vcftools \
  --gzvcf vcfs/panel_no-sibs_line-ids.vcf.gz \
  --max-missing 1 \
  --recode \
  --stdout > vcfs/panel_no-sibs_line-ids_no-missing.vcf
  
# compress
bcftools view \
  --output-type z \
  --output-file vcfs/panel_no-sibs_line-ids_no-missing.vcf.gz \
  vcfs/panel_no-sibs_line-ids_no-missing.vcf

# create index
bcftools index \
  --tbi vcfs/panel_no-sibs_line-ids_no-missing.vcf.gz
  
# get stats 
bcftools stats \
  vcfs/panel_no-sibs_line-ids_no-missing.vcf.gz \
  > stats/20200305_panel_no-sibs_no-missing.txt

# get basic counts
grep "^SN" stats/20200305_panel_no-sibs_no-missing.txt

Generate Haploview plots

Create BED sets filtered for MAF > 0.03, 0.05 and 0.10

maf_thresholds=$( echo 0.03 0.05 0.10 )

# Make new BEDs 
for i in $maf_thresholds ; do
  # make directory
  new_path=plink/20200716_panel_no-sibs_line-ids_no-missing/20200803_maf-$i ;
  # make directory
  if [ ! -d "$new_path" ]; then
    mkdir $new_path;
  fi
  # make BED set
  plink \
    --bfile plink/20200716_panel_no-sibs_line-ids_no-missing/20200716 \
    --make-bed \
    --double-id \
    --chr-set 24 no-xy \
    --maf $i \
    --out $new_path/20200803
done

Recode for Haploview

# Create output directory
mkdir plink/20200716_panel_no-sibs_line-ids_no-missing/20200803_hv_thinned

hv_thinned_path=plink/20200716_panel_no-sibs_line-ids_no-missing/20200803_hv_thinned

# Recode
for i in $maf_thresholds ; do
  new_path=$hv_thinned_path/$i ;
  # make directory
  if [ ! -d "$new_path" ]; then
    mkdir $new_path;
  fi 
  # recode 
  for j in $(seq 1 24); do
    plink \
      --bfile plink/20200716_panel_no-sibs_line-ids_no-missing/20200803_maf-$i/20200803 \
      --recode HV-1chr \
      --double-id \
      --chr-set 24 no-xy \
      --chr $j \
      --allele1234 \
      --thin-count 3000 \
      --out $hv_thinned_path/$i/20200803_chr-$j;
  done;
done

# Edit .ped files to remove asterisks
for i in $maf_thresholds ; do
  for j in $(find $hv_thinned_path/$i/20200803_chr-*.ped); do
    sed -i 's/\*/0/g' $j;
  done;
done  

# Edit .info files to make the SNP's bp position its ID
for i in $maf_thresholds; do
  for j in $(find $hv_thinned_path/$i/20200803_chr*.info); do
    outname=$(echo $j\_with-id);
    awk -v OFS="\t" {'print $2,$2'} $j > $outname;
  done;
done

Plot

NOTE: This code requires Haploview, which you will need to install on your system: https://www.broadinstitute.org/haploview/haploview

hv_path=/nfs/software/birney/Haploview.jar # edit to your Haploview path

mkdir plots/20200803_ld_thinned/

for i in $maf_thresholds; do
  # set output directory
  new_path=plots/20200803_ld_thinned/$i ;
  # make directory
  if [ ! -d "$new_path" ]; then
    mkdir $new_path;
  fi   
  for j in $(seq 1 24); do
    bsub -M 20000 -o log/20200803_hv_$i\_$j.out -e log/20200803_hv_$i\_$j.err \
    "java -Xms18G -Xmx18G -jar $hv_path \
      -memory 18000 \
      -pedfile $hv_thinned_path/$i/20200803_chr-$j.ped  \
      -info $hv_thinned_path/$i/20200803_chr-$j.info_with-id \
      -maxDistance 1000 \
      -ldcolorscheme DEFAULT \
      -ldvalues RSQ \
      -minMAF $i \
      -nogui \
      -svg \
      -out $new_path/$j";
  done;
done

These svg files can be converted to pdf using:

The full Haploview LD plots are available in the Supplementary Material.

By inspecting these LD plots at the MAF > 0.05 level, we discovered the following LD blocks worthy of further investigation:

  • 5:28181970-28970558 (788 Kb)
  • 6:29398579-32246747 (2.85 Mb)
  • 12:25336174-25384053 (48 Kb)
  • 14:12490842-12947083 (456 Kb)
  • 17:15557892-19561518 (4 Mb)
  • 21:6710074-7880374 (1.17 Mb)

See zoomed plots here:

Genotype heatmaps for high-LD regions

See which lines are causing the high-LD regions at the MAF > 0.05 threshold (i.e. from a sample of 63 diploid individuals, variants with an allele count (AC) of at least 7).

Read data into BED matrix into R

# Read in BED matrix
mikk_full <- gaston::read.bed.matrix(here("plink", "20200716_panel_no-sibs_line-ids_no-missing/20200716"),
                                     rds = NULL)

# Read in genotypes file
mikk_geno <- readr::read_tsv(file = here("plink", "20200716_panel_no-sibs_line-ids_no-missing/20200716_recode012.traw"),
                             progress = T,
                             col_names = T)

# rename IDs
colnames(mikk_geno)[7:length(colnames(mikk_geno))] <- mikk_full@ped$id

Extract target regions and build into list

# get coordinates
high_ld_chrs <- c(5, 6, 12, 14, 17, 21)
high_ld_start <- c(28385805, 29608514, 25340000, 12584614, 15559963, 6800261)
high_ld_end <- c(28798048, 32212235, 25372985, 12861147, 19553529, 7760258)

# build into list
counter <- 0
high_ld_lst <- lapply(high_ld_chrs, function(x){
  counter <<- counter + 1
  x <- list("chr" = x,
            "start" = high_ld_start[counter],
            "end" = high_ld_end[counter])
  # find indexes for SNPs with MAF > 0.05
  x[["target_inds"]] <- which(mikk_full@snps$chr == x[["chr"]] &
                         dplyr::between(mikk_full@snps$pos, x[["start"]], x[["end"]]) &
                         mikk_full@snps$maf > 0.05)
  x[["target_snps"]] <- mikk_geno[x[["target_inds"]], ]  
  # make matrix
  x[["geno_mat"]] <- as.matrix(x[["target_snps"]][, -(1:6)])
  return(x)
})
names(high_ld_lst) <- high_ld_chrs

# save to repo
saveRDS(high_ld_lst, here::here("mikk_genome", "data", "20200727_high_ld_list.rds"))

Plot

Genotypes were recoded to 0, 1, 2 for REF, HET, and HOM_ALT respectively.

Dark red = 2 Orange = 1 Yellow = 0

# Write function to create heatmap
get_heatmap = function(in_list){
  # Get order of samples
  sample_order = colnames(in_list[["target_snps"]])[-(1:6)]  
  # Sort by count
  sorted_order = names(sort(colSums(in_list[["geno_mat"]]), decreasing = T))
  # Get re-ordered indein_listes
  new_ind = match(sorted_order, sample_order)
  # Plot
  heatmap(in_list[["geno_mat"]][, new_ind], 
          Rowv = NA,
          Colv = NA,
          scale = "row",
          keep.dendro = F)  
}

Chr 5

knitr::include_graphics("hv_5_28181970-28970558.png")
x = high_ld_lst[["5"]]
get_heatmap(x)

Chr 6

knitr::include_graphics("hv_6_29398579-32246747.png")
x = high_ld_lst[["6"]]
get_heatmap(x)

Chr 12

knitr::include_graphics("hv_12_25336174-25384053.png")
x = high_ld_lst[["12"]]
get_heatmap(x)

Chr 14

knitr::include_graphics("hv_14_12490842-12947083.png")
x = high_ld_lst[["14"]]
get_heatmap(x)

Chr 17

knitr::include_graphics("hv_17_15557892-19561518.png")
x = high_ld_lst[["17"]]
get_heatmap(x)

Chr 21

knitr::include_graphics("hv_21_6710074-7880374.png")
x = high_ld_lst[["21"]]
get_heatmap(x)

LD decay

We want to compare the rate at which LD decays with inter-SNP distance between the MIKK panel and humans. This will give an indication of the resolution at which one can map genetic traits using the MIKK panel, provided that at least two lines have the same variant of interest.

Obtain 1000 Genomes dataset

Download from FTP

cd vcfs

wget -r -p -k --no-parent -cut-dirs=5 ftp://ftp.1000genomes.ebi.ac.uk/vol1/ftp/release/20130502/

Put list of files into list

find vcfs/ftp.1000genomes.ebi.ac.uk/ALL.chr*.vcf.gz > mikk_genome/data/20200205_vcfs.list

Merge VCFs

# Remove MT and Y from list 
sed -i '/MT/d' mikk_genome/data/20200205_vcfs.list

sed -i '/chrY/d' mikk_genome/data/20200205_vcfs.list

# run MergeVCFs 
java -jar /nfs/software/birney/picard-2.9.0/picard.jar MergeVcfs \
  I=mikk_genome/data/20200205_vcfs.list \
  O=vcfs/1gk_all.vcf.gz

Get mean LD within SNP-distance windows

0-10kb distance (main, MIKK v 1KG)

Rscript here: mikk_genome/code/scripts/20200727_r2_decay_mean_10kb-lim.R

MIKK

script=mikk_genome/code/scripts/20200727_r2_decay_mean_10kb-lim.R

mkdir ld/20200727_mean_r2_10kb-lim_mikk

for i in $(find ld/20200727_mikk_maf-0.10_window-50kb_no-missing/*.ld); do
  name=$(basename $i | cut -f1 -d".") ;
  out_dir=ld/20200727_mean_r2_10kb-lim_mikk ;
  bsub \
    -M 10000 \
    -o log/20200727_$name\_mean-r2_1kb-max.out \
    -e log/20200727_$name\_mean-r2_1kb-max.err \
    "Rscript --vanilla \
      $script \
      $i \
      $out_dir";
done

1KG

mkdir ld/20200727_mean_r2_10kb-lim_1kg

for i in $(find ld/20200727_1kg_maf-0.10_window-50kb_no-missing/*.ld); do
  name=$(basename $i | cut -f1 -d".") ;
  out_dir=ld/20200727_mean_r2_10kb-lim_1kg ;
  bsub \
    -M 30000 \
    -o log/20200727_$name\_mean-r2_10kb-max.out \
    -e log/20200727_$name\_mean-r2_10kb-max.err \
    "Rscript --vanilla \
      $script \
      $i \
      $out_dir";
done

0-1kb distance (inset, MIKK only)

Rscript: mikk_genome/code/scripts/20200803_r2_decay_mean_1gk_1kb-lim.R

mkdir ld/20200803_mean_r2_1kb-lim_mikk

out_dir=ld/20200803_mean_r2_1kb-lim_mikk
script=mikk_genome/code/scripts/20200803_r2_decay_mean_1gk_1kb-lim.R

for i in $(find ld/20200727_mikk_maf-0.10_window-50kb_no-missing/*ld); do
  name=$(basename $i | cut -f1 -d".");
  bsub \
    -M 30000 \
    -o log/20200803_$name\_mean-r2_1kb-max.out \
    -e log/20200803_$name\_mean-r2_1kb-max.err \
    "Rscript --vanilla \
      $script \
      $i \
      $out_dir";
done

Create LD plots in R

Main

Read in and process data

# Setup
require(here)
source(here("mikk_genome", "code", "scripts", "setup.R"))

# Create function to read in data and bind into single DF

read_n_bind = function(data_path_pref, dataset){
  # Set path
  path = paste(data_path_pref, dataset, sep = "")
  
  # Read in data
  data_files <- list.files(path,
                           full.names = T)
  data_files_trunc <- list.files(path)
  data_files_trunc <- gsub(".txt", "", data_files_trunc)
  
  data_list <- lapply(data_files, function(data_file){
    df <- read.delim(data_file,
                     sep = "\t",
                     header = T)
    return(df)
  })
  names(data_list) <- as.integer(data_files_trunc)
  
  # reorder
  data_list <- data_list[order(as.integer(names(data_list)))]
  
  # bind into DF
  out_df = dplyr::bind_rows(data_list, .id = "chr")
  out_df$chr <- factor(out_df$chr, levels = seq(1, 24))
  
  # get kb measure
  out_df$bin_bdr_kb <- out_df$bin_bdr / 1000  
  
  return(out_df)
}

# Run over both datasets
datasets = c("mikk", "1kg")
final_lst = lapply(datasets, function(x) read_n_bind("ld/20200727_mean_r2_10kb-lim_", x))
names(final_lst) = datasets

# Combine into single DF
r2_final_df <- dplyr::bind_rows(final_lst, .id = "dataset")
# Write table to repo
write.table(r2_final_df,
            file = here::here("mikk_genome", "data", "20200803_r2_10kb-lim.csv"),
            quote = F, sep = ",", row.names = F, col.names = T)

Plot

# Tidy data for final plot
r2_final_df$chr = factor(r2_final_df$chr, levels = seq(1, 24))
r2_final_df$dataset = toupper(r2_final_df$dataset)

# Plot
r2_plot_main = r2_final_df %>% ggplot() +
  geom_line(aes(bin_bdr_kb, mean, colour = chr)) +
  theme_cowplot() +
  xlab("Distance between SNPs (kb)") +
  ylab(bquote(.("Mean r")^2)) +
  facet_wrap(~dataset, nrow = 1, ncol = 2) +
  theme(panel.grid = element_blank(),
        strip.background = element_blank(),
        legend.position = c(0.9, .8)) +
  labs(colour = "Chromosome") +
  scale_y_continuous(breaks = c(0.1, 0.2, 0.3, 0.4, 0.5, 0.6),
                     limits = c(0.05, 0.6))

r2_plot_main

ggplotly(r2_plot_main)
the condition has length > 1 and only the first element will be usedthe condition has length > 1 and only the first element will be used
# Save plot to repo
ggsave(filename = paste("20200803_mean-r2_10kb-lim_1KGvMIKK_single", ".svg", sep = ""),
       plot = r2_plot_main,
       device = "svg",
       path = here::here("plots", "ld_decay"),
       width = 25,
       height = 13,
       units = "cm")

Inset

100-bp windows

# Read in data
r2_df_1kb_mikk = read_n_bind("ld/20200803_mean_r2_1kb-lim_", "mikk")
# Write table to repo
write.table(r2_df_1kb_mikk,
            file = here::here("mikk_genome", "data", "20200803_r2_1kb-lim_mikk.csv"),
            quote = F, sep = ",", row.names = F, col.names = T)
# Process for plotting
r2_df_1kb_mikk$chr <- factor(r2_df_1kb_mikk$chr, levels = seq(1, 24))

# Plot
r2_1kb_mikk = r2_df_1kb_mikk %>% ggplot() +
  geom_line(aes(bin_bdr, mean, colour = chr)) +
  theme_bw() +
  xlab("Distance beetween SNPs (bp)") +
  ylab(bquote(.("Mean r")^2)) +
  labs(colour = "Chromosome") +
  theme(panel.grid = element_blank(),
        axis.text = element_text(size = 12),
        axis.title = element_text(size = 14)) +
  guides(colour = F) +
  scale_x_continuous(limits = c(0, 1000)) +
  scale_y_continuous(breaks = c(0.1, 0.2, 0.3, 0.4, 0.5, 0.6),
                     limits = c(0.05, 0.6))

r2_1kb_mikk

# Save to repo
ggsave(filename = paste("20200803_mean-r2_1kb-lim_MIKK_inset_100bp-bins", ".png", sep = ""),
       plot = r2_1kb_mikk,
       device = "png",
       path = here::here("mikk_genome", "plots"),
       width = 10.88,
       height = 8,
       units = "cm",
       dpi = 500)

10-bp windows

For a finer resolution.

Get means for each bin
script=mikk_genome/code/scripts/20200724_r2_decay_mean_1gk_1kb-lim.R
out_dir=ld/20200727_mean_r2_1kb-lim_mikk

for in_file in $(find ld/20200727_mikk_maf-0.10_window-50kb_no-missing/*ld); do
  name=$(basename $in_file | cut -f1 -d".");
  bsub \
    -M 30000 \
    -o log/20200803_$name\_mean-r2_1kb-max.out \
    -e log/20200803_$name\_mean-r2_1kb-max.err \
    "Rscript \
      --vanilla \
      $script \
      $in_file \
      $out_dir";
done
# Combine in R
data_files <- list.files("ld/20200727_mean_r2_1kb-lim_mikk",
                         full.names = T)

data_files_trunc <- list.files("ld/20200727_mean_r2_1kb-lim_mikk")

data_files_trunc <- gsub(".txt", "", data_files_trunc)

data_list <- lapply(data_files, function(data_file){
  df <- read.delim(data_file,
                   sep = "\t",
                   header = T)
  return(df)
})

names(data_list) <- as.integer(data_files_trunc)

# reorder
data_list <- data_list[order(as.integer(names(data_list)))]

# bind into DF
r2_df_1kb_mikk <- dplyr::bind_rows(data_list, .id = "chr")
r2_df_1kb_mikk$chr <- factor(r2_df_1kb_mikk$chr, levels = seq(1, 24))

# write to table
write.table(r2_df_1kb_mikk, here::here("mikk_genome", "data", "20200803_mikk_ld-decay_1kb-lim_10bp-windows.txt"),
            quote = F, row.names = F, col.names = T, sep = "\t")
Plot
# Read in data
r2_df_1kb_mikk = read.table(here::here("data", "20200803_mikk_ld-decay_1kb-lim_10bp-windows.txt"),
                            header = T, sep = "\t", as.is = T)


# Factorise chromosomes
r2_df_1kb_mikk$chr <- factor(r2_df_1kb_mikk$chr, levels = seq(1, 24))

# Plot
r2_df_1kb_mikk %>% ggplot() +
  geom_line(aes(bin_bdr, mean, colour = chr)) +
  theme_bw() +
  xlab("Distance beetween SNPs (bp)") +
  ylab(bquote(.("Mean r")^2)) +
  labs(colour = "Chromosome") +
  theme(panel.grid = element_blank(),
        axis.text = element_text(size = 12),
        axis.title = element_text(size = 16)) +
  guides(colour = F) +
  scale_y_continuous(breaks = c(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7),
                     limits = c(0.05, 0.7))

# Save
ggsave(filename = paste("20200803_mean-r2_1kb-lim_MIKK_inset_10bp-windows", ".png", sep = ""),
       device = "png",
       path = here::here("mikk_genome", "plots"),
       width = 10.88,
       height = 8,
       units = "cm",
       dpi = 500)

MAF distribution MIKK v 1KG

Plot

in_mikk <- "../maf/20200727_mikk_no-missing.frq"
in_1kg <- "../maf/20200727_1kg_no-missing.frq"
#out_file <- args[3]

## MIKK
maf_mikk <- readr::read_delim(in_mikk,
                             delim = " ",
                             trim_ws = T,
                             col_types = cols_only(MAF = col_double()))
maf_mikk$dataset <- "MIKK"

## 1KG
maf_1kg <- readr::read_delim(in_1kg,
                             delim = " ",
                             trim_ws = T,
                             col_types = cols_only(MAF = col_double()))
maf_1kg$dataset <- "1KG"

## Bind
maf_final <- rbind(maf_mikk, maf_1kg)

# Plot
maf_plot = maf_final %>%
  ggplot() +
    geom_histogram(aes(x = MAF,
                       y=0.01*..density..,
                       fill = dataset),
                   binwidth = 0.01) +
    theme_cowplot() +
    guides(fill = F) +
    facet_wrap(~dataset, nrow = 1, ncol = 2) +
    xlab("Minor allele frequencies") +
    ylab("Density") +
    theme(strip.background = element_blank(),
          strip.text = element_text(size = 14,
                                    face = "bold"))

LD decay without labels

r2_plot_main_nolabs = r2_final_df %>% ggplot() +
  geom_line(aes(bin_bdr_kb, mean, colour = chr)) +
  theme_cowplot() +
  xlab("Distance between SNPs (kb)") +
  ylab(bquote(.("Mean r")^2)) +
  facet_wrap(~dataset, nrow = 1, ncol = 2) +
  theme(panel.grid = element_blank(),
        strip.background = element_blank(),
        strip.text.x = element_blank(),
        legend.position = c(.9, .8),
        legend.key.size = unit(9, "points"),
        legend.title = element_text(size = 9),
        legend.text = element_text(size = 9)) +
  labs(colour = "Chromosome") +
  scale_y_continuous(breaks = c(0.1, 0.2, 0.3, 0.4, 0.5, 0.6),
                     limits = c(0.05, 0.6))

Combine with LD decay for final figure

final_fig = cowplot::ggdraw() +
  draw_plot(maf_plot,
            x = 0, y = .7, width = 1, height = .3) +
  draw_plot(r2_plot_main_nolabs,
            x = 0, y = 0, width = 1, height = .7) +
  draw_plot_label(label = c("A", "B"), size = 15,
                  x = c(0, 0), y = c(1, .7))
out_path = here::here("plots", "ld_decay", "20210305_final_figure.png")

ggsave(out_path,
       plot = final_fig,
       device = "png",
       width = 23,
       height = 22,
       units = "cm",
       dpi = 500)
knitr::include_graphics(here::here("plots", "ld_decay", "20210305_final_figure.png"))

Investigation of LD decay in chr 2

Chromsome 2 has an obviously faster LD decay than the other chromosomes. We explore some possible reasons for this.

Get lengths of each chr on bash

seq 1 24 > tmp1.txt

grep ">" refs/Oryzias_latipes.ASM223467v1.dna.toplevel.fa | scut -f6 -d":" | head -24 > tmp2.txt

paste tmp1.txt tmp2.txt > mikk_genome/data/Oryzias_latipes.ASM223467v1.dna.toplevel.fa_chr_counts.txt

Get proportion of each chromosome covered by exons using biomaRt

# Load libraries
library(here)
source(here::here("code", "scripts", "setup.R"))

# Get length of chromosomes
chr_counts <- readr::read_tsv(here::here("data",
                                         "Oryzias_latipes.ASM223467v1.dna.toplevel.fa_chr_counts.txt"),
                              col_names = c("chr", "length"))

# List marts 
listMarts()

# Select database and list datasets within
ensembl_mart <- useMart("ENSEMBL_MART_ENSEMBL")

# Select dataset
ensembl_olat <- useDataset("olatipes_gene_ensembl", mart = ensembl_mart)
olat_mart = useEnsembl(biomart = "ensembl", dataset = "olatipes_gene_ensembl")
# Get attributes of interest (exon ID, chr, start, end)
exons <- getBM(attributes = c("chromosome_name", "ensembl_gene_id", "ensembl_transcript_id", "transcript_start", "transcript_end", "transcript_length", "ensembl_exon_id", "rank", "strand", "exon_chrom_start", "exon_chrom_end", "cds_start", "cds_end"),
               mart = olat_mart)

# Factorise chr so it's in the right order
chrs <- unique(exons$chromosome_name)
auto_range <- range(as.integer(chrs), na.rm = T)
non_auto <- chrs[is.na(as.integer(chrs))]
chr_order <- c(seq(auto_range[1], auto_range[2]), non_auto)
exons$chromosome_name <- factor(exons$chromosome_name, levels = chr_order)

# Convert into list
exons_lst <- split(exons, f = exons$chromosome_name)

# Get mean length of exons per chromosome
exons_lst <- lapply(exons_lst, function(chr){
  chr <- chr %>%
    dplyr::mutate(exon_length = (exon_chrom_end - exon_chrom_start) + 1,
                  transcript_total_length = (transcript_end - transcript_start) + 1)
  return(chr)
})

# Get total length of chr covered by exons
exon_lengths <- lapply(exons_lst, function(chr){
  # create list of start pos to end pos sequences for each exon
  out_list <- apply(chr, 1, function(exon) {
    seq(exon[["exon_chrom_start"]], exon[["exon_chrom_end"]])
  })
  # combine list of vectors into single vector and get only unique numbers
  out_vec <- unique(unlist(out_list))
  # get length of out_vec and put it into data frame
  out_final <- data.frame("exon_cov" = length(out_vec))
  return(out_final)
})

# combine into single DF
exons_len_df <- dplyr::bind_rows(exon_lengths, .id = "chr") %>% 
  dplyr::filter(chr != "MT") %>% 
  dplyr::mutate(chr = as.integer(chr))

# join with chr_counts and get proportion of chr covered by exons
chr_stats <- dplyr::left_join(chr_counts, exons_len_df, by = "chr") %>% 
  dplyr::mutate(prop_cov_exon = exon_cov / length)
# convert chr to factor for plotting
chr_stats$chr <- factor(chr_stats$chr)

Get SNP counts per megabase

Get counts

bcftools index \
  --stats \
  ../vcfs/panel_no-sibs_line-ids_no-missing_bi-snps_with-af.vcf.gz \
    > data/20201106_non-missing_bi-snp_count.txt

Read SNP counts data into R

snp_counts = read.table(here::here("data", "20201106_non-missing_bi-snp_count.txt"),
                        sep = "\t",
                        col.names = c("chr", "length", "snp_count")) %>% 
  # create megabase column
  dplyr::mutate(megabases = length / 1e6,
                snps_per_megabase = snp_count / megabases) %>% 
  # remove MT
  dplyr::filter(chr != "MT") %>% 
  # turn chr column into integer
  dplyr::mutate(chr = as.factor(as.integer(chr)))

Combine SNP counts with exon proportion counts

chr_df = snp_counts %>% 
  dplyr::full_join(chr_stats, by = c("chr", "length"))

# Create recode vector
recode_vec = c("Non-missing, biallelic SNPs per megabase",
               "Proportion of chromosome covered by exons")
names(recode_vec) = c("snps_per_megabase",
                      "prop_cov_exon")

Plot

chr_df %>% 
  tidyr::pivot_longer(cols = c(snps_per_megabase, prop_cov_exon), 
                      names_to = "variable",
                      values_to = "values") %>% 
  dplyr::mutate(variable = dplyr::recode(variable, !!!recode_vec)) %>% 
  ggplot() +
    geom_col(aes(chr, values, fill = chr)) +
    guides(fill = F) + 
    xlab("Chromosome") +
    ylab(NULL) +
    theme_bw() +
    facet_wrap(~variable,
               nrow = 2, ncol = 1,
               scales = "free_y")
chr_df %>% 
  ggplot(aes(snps_per_megabase, prop_cov_exon, colour = chr, label = chr)) +
  geom_point() +
  geom_text(hjust = -0.5) +
  theme_bw() +
  guides(colour = F) +
  xlab("Non-missing, biallelic SNPs per megabase") +
  ylab("Proportion of chromosome covered by exons")
# Save to repo
ggsave(filename = paste("20201106_snps-per-mb_v_exon-props", ".png", sep = ""),
       device = "png",
       path = here("mikk_genome", "plots"),
       width = 24,
       height = 20,
       units = "cm",
       dpi = 500)

Calculate correlation

cor.test(chr_df$snps_per_megabase, chr_df$prop_cov_exon, method = "spearman")
LS0tCnRpdGxlOiAiTGlua2FnZSBkaXNlcXVpbGlicml1bSIKZGF0ZTogJ2ByIGZvcm1hdChTeXMuRGF0ZSgpKWAnCm91dHB1dDogaHRtbF9ub3RlYm9vawplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQojb3V0cHV0OgojICBodG1sX2RvY3VtZW50OgojICAgIHRvYzogdHJ1ZQojICAgIHRvY19mbG9hdDogdHJ1ZQojICAgIGRldjogJ3N2ZycKIyAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKIyAgICBwYW5kb2NfYXJnczogLS1sdWEtZmlsdGVyPWNvbG9yLXRleHQubHVhCiMgICAgaGlnaGxpZ2h0OiBweWdtZW50cwotLS0KCiMgU2V0dXAKCiMjIENyZWF0ZSBkaXJlY3Rvcnkgc3RydWN0dXJlIGFuZCBjbG9uZSByZXBvCgooV29ya2luZyBkaXJlY3Rvcnkgb24gRUJJIGNsdXN0ZXI6IGAvaHBzL3Jlc2VhcmNoMS9iaXJuZXkvdXNlcnMvaWFuL21pa2tfcGFwZXJgKQoKYGBge2Jhc2gsIGV2YWwgPSBGfQojIG1vdmUgdG8gd29ya2luZyBkaXJlY3RvcnkKY2QgL3lvdXIvd29ya2luZy9kaXJlY3RvcnkKIyBjbG9uZSBnaXQgcmVwb3NpdG9yeQpnaXQgY2xvbmUgaHR0cHM6Ly9naXRodWIuY29tL0lhbi1CcmV0dGVsbC9taWtrX2dlbm9tZS5naXQKYGBgCgojIyBDcmVhdGUgY29uZGEgZXZpcm9ubWVudAoKYGBge2Jhc2gsIGV2YWwgPSBGfQpjb25kYSBlbnYgY3JlYXRlIFwKICAtbiBtaWtrX2VudiBcCiAgLWYgbWlra19nZW5vbWUvY29kZS9jb25maWcvY29uZGFfZW52LnltbAogIApjb25kYSBhY3RpdmF0ZSBtaWtrX2VudgpgYGAKCiMjIFNldHVwIGBSYAoKYGBge3IsIG1lc3NhZ2UgPSBGLCB3YXJuaW5nID0gRn0KIyBMb2FkIHJlcXVpcmVkIGxpYnJhcmllcwpyZXF1aXJlKGhlcmUpCnNvdXJjZShoZXJlOjpoZXJlKCJjb2RlIiwgInNjcmlwdHMiLCAibGRfZGVjYXkiLCAic291cmNlLlIiKSkKYGBgCgoKIyMgQ29weSBNSUtLIHBhbmVsIFZDRiBpbnRvIHdvcmtpbmcgZGlyZWN0b3J5CgooU2VlIHN1cHBsZW1lbnRhcnkgbWF0ZXJpYWwgZm9yIGhvdyBWQ0Ygd2FzIGdlbmVyYXRlZC4pCgpgYGB7YmFzaCwgZXZhbCA9IEZ9CiMgY3JlYXRlIGRpcmVjdG9yeSBmb3IgVkNGcwpta2RpciB2Y2ZzCgojIENvcHkgaW50byB3b3JraW5nIGRpcmVjdG9yeQpjcCAvbmZzL3Jlc2VhcmNoMS9iaXJuZXkvcHJvamVjdHMvbWVkYWthL2luYnJlZF9wYW5lbC9tZWRha2EtYWxpZ25tZW50cy1yZWxlYXNlLTk0L3ZjZi9tZWRha2FfaW5icmVkX3BhbmVsX2Vuc2VtYmxfbmV3X3JlZmVyZW5jZV9yZWxlYXNlXzk0LnZjZiogdmNmcwpgYGAKCiMjIEtleS12YWx1ZSBmaWxlIGZvciBjcmFtIElEIHRvIGxpbmUgSUQKCmBtaWtrX2dlbm9tZS9kYXRhLzIwMjAwMjA2X2NyYW1faWRfdG9fbGluZV9pZC50eHRgCgojIyBSZW1vdmUgc2libGluZyBsaW5lcyBhbmQgcmVwbGljYXRlcwoKKipGdWxsIGxpc3Qgb2YgODAgZXh0YW50IE1JS0sgcGFuZWwgbGluZXMqKjogYG1pa2tfZ2Vub21lL2RhdGEvMjAyMDAyMTBfcGFuZWxfbGluZXNfZnVsbC50eHRgCgoqKk5vdGUqKjogTGluZSBgMTMwLTJgIGlzIG1pc3NpbmcgZnJvbSB0aGUgTUlLSyBwYW5lbCBWQ0YuCgpJZGVudGlmeSBzaWJsaW5nIGxpbmVzCgpgYGB7YmFzaCwgZXZhbCA9IEZ9CmNhdCBtaWtrX2dlbm9tZS9kYXRhLzIwMjAwMjEwX3BhbmVsX2xpbmVzX2Z1bGwudHh0IHwgY3V0IC1mMSAtZCItIiB8IHNvcnQgfCB1bmlxIC1kCmBgYAoKLSAxMDYKLSAxMQotIDExNwotIDEzMQotIDEzMgotIDEzNQotIDE0Ci0gMTQwCi0gMjMKLSAzOQotIDQKLSA0MAotIDU5Ci0gNjkKLSA3MgotIDgwCgpPbmx5IGtlZXAgZmlyc3Qgc2libGluZyBsaW5lICggc3VmZml4IF8xKTsgbWFudWFsbHkgcmVtb3ZlIGFsbCBvdGhlcnMgYW5kIHdyaXRlIGxpc3Qgb2Ygbm9uLXNpYmxpbmcgbGluZXMgdG8gaGVyZTogYG1pa2tfZ2Vub21lL2RhdGEvMjAyMDAyMjdfcGFuZWxfbGluZXNfbm8tc2licy50eHRgLiA2NCBsaW5lcyB0b3RhbC4KCkV4Y2x1ZGVkIHNpYmxpbmcgbGluZXMgaGVyZTogYG1pa2tfZ2Vub21lL2RhdGEvMjAyMDAyMjdfcGFuZWxfbGluZXNfZXhjbHVkZWQudHh0YC4gMTYgbGluZXMgdG90YWwuCgpSZXBsYWNlIGFsbCBkYXNoZXMgd2l0aCB1bmRlcnNjb3JlcyB0byBtYXRjaCBgbWlra19nZW5vbWUvZGF0YS8yMDIwMDIwNl9jcmFtX2lkX3RvX2xpbmVfaWQudHh0YCBrZXkgZmlsZQpgYGB7YmFzaCwgZXZhbCA9IEZ9CnNlZCAncy8tL18vZycgbWlra19nZW5vbWUvZGF0YS8yMDIwMDIyN19wYW5lbF9saW5lc19uby1zaWJzLnR4dCBcCiAgPiBtaWtrX2dlbm9tZS9kYXRhLzIwMjAwMjI3X3BhbmVsX2xpbmVzX25vLXNpYnNfdXMudHh0CmBgYAoKRXh0cmFjdCB0aGUgbGluZXMgdG8ga2VlcCBmcm9tIHRoZSBrZXkgZmlsZS4KYGBge2Jhc2gsIGV2YWwgPSBGfQphd2sgICdGTlI9PU5SIHtmMVskMF07IG5leHR9ICQyIGluIGYxJyBcCiAgbWlra19nZW5vbWUvZGF0YS8yMDIwMDIyN19wYW5lbF9saW5lc19uby1zaWJzX3VzLnR4dCBcCiAgbWlra19nZW5vbWUvZGF0YS8yMDIwMDIwNl9jcmFtX2lkX3RvX2xpbmVfaWQudHh0IFwKICAgID4gbWlra19nZW5vbWUvZGF0YS8yMDIwMDIyN19jcmFtMmxpbmVfbm8tc2licy50eHQKYGBgCgpIYXMgNjYgbGluZXMgaW5zdGVhZCBvZiA2MyAoNjQgbGluZXMgbWludXMgYDEzMC0yYCwgd2hpY2ggaXNuJ3QgaW4gdGhlIFZDRiksIHNvIHRoZXJlIG11c3QgYmUgcmVwbGljYXRlcyBGaW5kIG91dCB3aGljaCBvbmVzOgoKYGBge2Jhc2gsIGV2YWwgPSBGfQpjYXQgbWlra19nZW5vbWUvZGF0YS8yMDIwMDIyN19jcmFtMmxpbmVfbm8tc2licy50eHQgfCBjdXQgLWYyIHwgY3V0IC1mMSAtZCJfIiB8IHNvcnQgfCB1bmlxIC1kCmBgYAoKMzIKNzEKODQKCk1hbnVhbGx5IHJlbW92ZWQgZHVwbGljYXRlIGxpbmVzIChgbWlra19nZW5vbWUvZGF0YS8yMDIwMDIyN19kdXBsaWNhdGVzX2V4Y2x1ZGVkLnR4dGApOgoKKiAyNDI3MV83IzUJMzJfMgoqIDI0MjcxXzgjNAk3MV8xCiogMjQyNTlfMSMxCTg0XzIKCkZpbmFsIG5vLXNpYmxpbmctbGluZXMgQ1JBTS10by1saW5lSUQga2V5IGZpbGU6IGBtaWtrX2dlbm9tZS9kYXRhLzIwMjAwMjI3X2NyYW0ybGluZV9uby1zaWJzLnR4dGAKCiMgQ3JlYXRlIE1JS0sgcGFuZWwgVkNGIHdpdGggbm8gc2libGluZyBsaW5lcwoKYGBge2Jhc2gsIGV2YWwgPSBGfQojIGNyZWF0ZSBuby1zaWJzIGZpbGUgd2l0aCBDUkFNIElEIG9ubHkKY3V0IC1mMSBtaWtrX2dlbm9tZS9kYXRhLzIwMjAwMjI3X2NyYW0ybGluZV9uby1zaWJzLnR4dCBcCiAgPiBtaWtrX2dlbm9tZS9kYXRhLzIwMjAwMjI3X2NyYW0ybGluZV9uby1zaWJzX2NyYW0tb25seS50eHQKICAKIyBtYWtlIG5ldyBWQ0YgaGF2aW5nIGZpbHRlcmVkIG91dCBub24tTUlLSyBhbmQgc2libGluZyBsaW5lcwpiY2Z0b29scyB2aWV3IFwKICAtLW91dHB1dC1maWxlIHZjZnMvcGFuZWxfbm8tc2licy52Y2YgXAogIC0tc2FtcGxlcy1maWxlIG1pa2tfZ2Vub21lL2RhdGEvMjAyMDAyMjdfY3JhbTJsaW5lX25vLXNpYnNfY3JhbS1vbmx5LnR4dCBcCiAgdmNmcy9tZWRha2FfaW5icmVkX3BhbmVsX2Vuc2VtYmxfbmV3X3JlZmVyZW5jZV9yZWxlYXNlXzk0LnZjZgogIAojIHJlY29kZSB3aXRoIGxpbmUgSURzCmJjZnRvb2xzIHJlaGVhZGVyIFwKICAtLW91dHB1dCB2Y2ZzL3BhbmVsX25vLXNpYnNfbGluZS1pZHMudmNmIFwKICAtLXNhbXBsZXMgbWlra19nZW5vbWUvZGF0YS8yMDIwMDIyN19jcmFtMmxpbmVfbm8tc2licy50eHQgXAogIHZjZnMvcGFuZWxfbm8tc2licy52Y2YKICAKIyBjb21wcmVzcwpiY2Z0b29scyB2aWV3IFwKICAtLW91dHB1dC10eXBlIHogXAogIC0tb3V0cHV0LWZpbGUgdmNmcy9wYW5lbF9uby1zaWJzX2xpbmUtaWRzLnZjZi5neiBcCiAgdmNmcy9wYW5lbF9uby1zaWJzX2xpbmUtaWRzLnZjZgogIAojIGluZGV4CmJjZnRvb2xzIGluZGV4IFwKICAtLXRiaSBcCiAgdmNmcy9wYW5lbF9uby1zaWJzX2xpbmUtaWRzLnZjZi5negoKIyBnZXQgc3RhdHMKbWtkaXIgc3RhdHMKCmJjZnRvb2xzIHN0YXRzIFwKICB2Y2ZzL3BhbmVsX25vLXNpYnNfbGluZS1pZHMudmNmLmd6IFwKICA+IHN0YXRzLzIwMjAwMzA1X3BhbmVsX25vLXNpYnMudHh0CgojIyBnZXQgYmFzaWMgY291bnRzCmdyZXAgIl5TTiIgc3RhdHMvMjAyMDAzMDVfcGFuZWxfbm8tc2licy50eHQKYGBgCgojIyBNYWtlIGEgdmVyc2lvbiB3aXRoIG5vIG1pc3NpbmcgdmFyaWFudHMKCmBgYHtiYXNoLCBldmFsID0gRn0KdmNmdG9vbHMgXAogIC0tZ3p2Y2YgdmNmcy9wYW5lbF9uby1zaWJzX2xpbmUtaWRzLnZjZi5neiBcCiAgLS1tYXgtbWlzc2luZyAxIFwKICAtLXJlY29kZSBcCiAgLS1zdGRvdXQgPiB2Y2ZzL3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZy52Y2YKICAKIyBjb21wcmVzcwpiY2Z0b29scyB2aWV3IFwKICAtLW91dHB1dC10eXBlIHogXAogIC0tb3V0cHV0LWZpbGUgdmNmcy9wYW5lbF9uby1zaWJzX2xpbmUtaWRzX25vLW1pc3NpbmcudmNmLmd6IFwKICB2Y2ZzL3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZy52Y2YKCiMgY3JlYXRlIGluZGV4CmJjZnRvb2xzIGluZGV4IFwKICAtLXRiaSB2Y2ZzL3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZy52Y2YuZ3oKICAKIyBnZXQgc3RhdHMgCmJjZnRvb2xzIHN0YXRzIFwKICB2Y2ZzL3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZy52Y2YuZ3ogXAogID4gc3RhdHMvMjAyMDAzMDVfcGFuZWxfbm8tc2lic19uby1taXNzaW5nLnR4dAoKIyBnZXQgYmFzaWMgY291bnRzCmdyZXAgIl5TTiIgc3RhdHMvMjAyMDAzMDVfcGFuZWxfbm8tc2lic19uby1taXNzaW5nLnR4dApgYGAKCiMgR2VuZXJhdGUgSGFwbG92aWV3IHBsb3RzCgojIyBDcmVhdGUgYHBsaW5rYCBkYXRhc2V0IGZyb20gbm8tc2liLWxpbmVzLCBuby1taXNzaW5nIFZDRgoKYGBge2Jhc2gsIGV2YWwgPSBGfQpta2RpciBwbGluay8yMDIwMDcxNl9wYW5lbF9uby1zaWJzX2xpbmUtaWRzX25vLW1pc3NpbmcKCiMgbWFrZSBCRUQgIApwbGluayBcCiAgLS12Y2YgdmNmcy9wYW5lbF9uby1zaWJzX2xpbmUtaWRzX25vLW1pc3NpbmcudmNmLmd6IFwKICAtLW1ha2UtYmVkIFwKICAtLWRvdWJsZS1pZCBcCiAgLS1zbnBzLW9ubHkgXAogIC0tYmlhbGxlbGljLW9ubHkgXAogIC0tY2hyLXNldCAyNCBuby14eSBcCiAgLS1jaHIgMS0yNCBcCiAgLS1vdXQgcGxpbmsvMjAyMDA3MTZfcGFuZWxfbm8tc2lic19saW5lLWlkc19uby1taXNzaW5nLzIwMjAwNzE2CiAgCiMgcmVjb2RlIGZvciAwMTIgdHJhbnNwb3NlZApwbGluayBcCiAgLS1iZmlsZSBwbGluay8yMDIwMDcxNl9wYW5lbF9uby1zaWJzX2xpbmUtaWRzX25vLW1pc3NpbmcvMjAyMDA3MTYgXAogIC0tcmVjb2RlIEEtdHJhbnNwb3NlIFwKICAtLW91dCBwbGluay8yMDIwMDcxNl9wYW5lbF9uby1zaWJzX2xpbmUtaWRzX25vLW1pc3NpbmcvMjAyMDA3MTZfcmVjb2RlMDEyCiMgY3JlYXRlcyBwbGluay8yMDIwMDcxNl9wYW5lbF9uby1zaWJzX2xpbmUtaWRzX25vLW1pc3NpbmcvMjAyMDA3MTZfcmVjb2RlMDEyLnRyYXcgIApgYGAKCiMjIENyZWF0ZSBCRUQgc2V0cyBmaWx0ZXJlZCBmb3IgTUFGID4gMC4wMywgMC4wNSBhbmQgMC4xMAoKYGBge2Jhc2gsIGV2YWwgPSBGfQptYWZfdGhyZXNob2xkcz0kKCBlY2hvIDAuMDMgMC4wNSAwLjEwICkKCiMgTWFrZSBuZXcgQkVEcyAKZm9yIGkgaW4gJG1hZl90aHJlc2hvbGRzIDsgZG8KICAjIG1ha2UgZGlyZWN0b3J5CiAgbmV3X3BhdGg9cGxpbmsvMjAyMDA3MTZfcGFuZWxfbm8tc2lic19saW5lLWlkc19uby1taXNzaW5nLzIwMjAwODAzX21hZi0kaSA7CiAgIyBtYWtlIGRpcmVjdG9yeQogIGlmIFsgISAtZCAiJG5ld19wYXRoIiBdOyB0aGVuCiAgICBta2RpciAkbmV3X3BhdGg7CiAgZmkKICAjIG1ha2UgQkVEIHNldAogIHBsaW5rIFwKICAgIC0tYmZpbGUgcGxpbmsvMjAyMDA3MTZfcGFuZWxfbm8tc2lic19saW5lLWlkc19uby1taXNzaW5nLzIwMjAwNzE2IFwKICAgIC0tbWFrZS1iZWQgXAogICAgLS1kb3VibGUtaWQgXAogICAgLS1jaHItc2V0IDI0IG5vLXh5IFwKICAgIC0tbWFmICRpIFwKICAgIC0tb3V0ICRuZXdfcGF0aC8yMDIwMDgwMwpkb25lCmBgYAoKIyMgUmVjb2RlIGZvciBIYXBsb3ZpZXcKCmBgYHtiYXNoLCBldmFsID0gRn0KIyBDcmVhdGUgb3V0cHV0IGRpcmVjdG9yeQpta2RpciBwbGluay8yMDIwMDcxNl9wYW5lbF9uby1zaWJzX2xpbmUtaWRzX25vLW1pc3NpbmcvMjAyMDA4MDNfaHZfdGhpbm5lZAoKaHZfdGhpbm5lZF9wYXRoPXBsaW5rLzIwMjAwNzE2X3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZy8yMDIwMDgwM19odl90aGlubmVkCgojIFJlY29kZQpmb3IgaSBpbiAkbWFmX3RocmVzaG9sZHMgOyBkbwogIG5ld19wYXRoPSRodl90aGlubmVkX3BhdGgvJGkgOwogICMgbWFrZSBkaXJlY3RvcnkKICBpZiBbICEgLWQgIiRuZXdfcGF0aCIgXTsgdGhlbgogICAgbWtkaXIgJG5ld19wYXRoOwogIGZpIAogICMgcmVjb2RlIAogIGZvciBqIGluICQoc2VxIDEgMjQpOyBkbwogICAgcGxpbmsgXAogICAgICAtLWJmaWxlIHBsaW5rLzIwMjAwNzE2X3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZy8yMDIwMDgwM19tYWYtJGkvMjAyMDA4MDMgXAogICAgICAtLXJlY29kZSBIVi0xY2hyIFwKICAgICAgLS1kb3VibGUtaWQgXAogICAgICAtLWNoci1zZXQgMjQgbm8teHkgXAogICAgICAtLWNociAkaiBcCiAgICAgIC0tYWxsZWxlMTIzNCBcCiAgICAgIC0tdGhpbi1jb3VudCAzMDAwIFwKICAgICAgLS1vdXQgJGh2X3RoaW5uZWRfcGF0aC8kaS8yMDIwMDgwM19jaHItJGo7CiAgZG9uZTsKZG9uZQoKIyBFZGl0IC5wZWQgZmlsZXMgdG8gcmVtb3ZlIGFzdGVyaXNrcwpmb3IgaSBpbiAkbWFmX3RocmVzaG9sZHMgOyBkbwogIGZvciBqIGluICQoZmluZCAkaHZfdGhpbm5lZF9wYXRoLyRpLzIwMjAwODAzX2Noci0qLnBlZCk7IGRvCiAgICBzZWQgLWkgJ3MvXCovMC9nJyAkajsKICBkb25lOwpkb25lICAKCiMgRWRpdCAuaW5mbyBmaWxlcyB0byBtYWtlIHRoZSBTTlAncyBicCBwb3NpdGlvbiBpdHMgSUQKZm9yIGkgaW4gJG1hZl90aHJlc2hvbGRzOyBkbwogIGZvciBqIGluICQoZmluZCAkaHZfdGhpbm5lZF9wYXRoLyRpLzIwMjAwODAzX2NociouaW5mbyk7IGRvCiAgICBvdXRuYW1lPSQoZWNobyAkalxfd2l0aC1pZCk7CiAgICBhd2sgLXYgT0ZTPSJcdCIgeydwcmludCAkMiwkMid9ICRqID4gJG91dG5hbWU7CiAgZG9uZTsKZG9uZQpgYGAKCiMjIFBsb3QKCioqTk9URSoqOiBUaGlzIGNvZGUgcmVxdWlyZXMgYEhhcGxvdmlld2AsIHdoaWNoIHlvdSB3aWxsIG5lZWQgdG8gaW5zdGFsbCBvbiB5b3VyIHN5c3RlbTogPGh0dHBzOi8vd3d3LmJyb2FkaW5zdGl0dXRlLm9yZy9oYXBsb3ZpZXcvaGFwbG92aWV3PgoKYGBge2Jhc2gsIGV2YWwgPSBGfQpodl9wYXRoPS9uZnMvc29mdHdhcmUvYmlybmV5L0hhcGxvdmlldy5qYXIgIyBlZGl0IHRvIHlvdXIgSGFwbG92aWV3IHBhdGgKCm1rZGlyIHBsb3RzLzIwMjAwODAzX2xkX3RoaW5uZWQvCgpmb3IgaSBpbiAkbWFmX3RocmVzaG9sZHM7IGRvCiAgIyBzZXQgb3V0cHV0IGRpcmVjdG9yeQogIG5ld19wYXRoPXBsb3RzLzIwMjAwODAzX2xkX3RoaW5uZWQvJGkgOwogICMgbWFrZSBkaXJlY3RvcnkKICBpZiBbICEgLWQgIiRuZXdfcGF0aCIgXTsgdGhlbgogICAgbWtkaXIgJG5ld19wYXRoOwogIGZpICAgCiAgZm9yIGogaW4gJChzZXEgMSAyNCk7IGRvCiAgICBic3ViIC1NIDIwMDAwIC1vIGxvZy8yMDIwMDgwM19odl8kaVxfJGoub3V0IC1lIGxvZy8yMDIwMDgwM19odl8kaVxfJGouZXJyIFwKICAgICJqYXZhIC1YbXMxOEcgLVhteDE4RyAtamFyICRodl9wYXRoIFwKICAgICAgLW1lbW9yeSAxODAwMCBcCiAgICAgIC1wZWRmaWxlICRodl90aGlubmVkX3BhdGgvJGkvMjAyMDA4MDNfY2hyLSRqLnBlZCAgXAogICAgICAtaW5mbyAkaHZfdGhpbm5lZF9wYXRoLyRpLzIwMjAwODAzX2Noci0kai5pbmZvX3dpdGgtaWQgXAogICAgICAtbWF4RGlzdGFuY2UgMTAwMCBcCiAgICAgIC1sZGNvbG9yc2NoZW1lIERFRkFVTFQgXAogICAgICAtbGR2YWx1ZXMgUlNRIFwKICAgICAgLW1pbk1BRiAkaSBcCiAgICAgIC1ub2d1aSBcCiAgICAgIC1zdmcgXAogICAgICAtb3V0ICRuZXdfcGF0aC8kaiI7CiAgZG9uZTsKZG9uZQpgYGAKClRoZXNlIGBzdmdgIGZpbGVzIGNhbiBiZSBjb252ZXJ0ZWQgdG8gYHBkZmAgdXNpbmc6CgoqIDxodHRwczovL3d3dy56YW16YXIuY29tLz4gZm9yIGZpbGVzID4gMzAgTUIgKGNociAxKSAtIG5vdGUgbGltaXQgb24gbnVtYmVyIG9mIGZpbGVzIHlvdSBjYW4gY29udmVydAoqIDxodHRwczovL29ubGluZWNvbnZlcnRmcmVlLmNvbS9jb252ZXJ0LWZvcm1hdC9zdmctdG8tcGRmLz4gZm9yIHRoZSByZXN0CgpUaGUgZnVsbCBIYXBsb3ZpZXcgTEQgcGxvdHMgYXJlIGF2YWlsYWJsZSBpbiB0aGUgU3VwcGxlbWVudGFyeSBNYXRlcmlhbC4KCkJ5IGluc3BlY3RpbmcgdGhlc2UgTEQgcGxvdHMgYXQgdGhlIGBNQUYgPiAwLjA1YCBsZXZlbCwgd2UgZGlzY292ZXJlZCB0aGUgZm9sbG93aW5nIExEIGJsb2NrcyB3b3J0aHkgb2YgZnVydGhlciBpbnZlc3RpZ2F0aW9uOgoKKiA1OjI4MTgxOTcwLTI4OTcwNTU4ICg3ODggS2IpCiogNjoyOTM5ODU3OS0zMjI0Njc0NyAoMi44NSBNYikKKiAxMjoyNTMzNjE3NC0yNTM4NDA1MyAoNDggS2IpCiogMTQ6MTI0OTA4NDItMTI5NDcwODMgKDQ1NiBLYikKKiAxNzoxNTU1Nzg5Mi0xOTU2MTUxOCAoNCBNYikKKiAyMTo2NzEwMDc0LTc4ODAzNzQgKDEuMTcgTWIpCgpTZWUgem9vbWVkIHBsb3RzIGhlcmU6CgpgYGB7ciwgZWNobyA9IEYsIGZpZy5jYXAgPSAiNToyODE4MTk3MC0yODk3MDU1OCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJodl81XzI4MTgxOTcwLTI4OTcwNTU4LnBuZyIpCmBgYAoKYGBge3IsIGVjaG8gPSBGLCBmaWcuY2FwID0gIjY6MjkzOTg1NzktMzIyNDY3NDcifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaHZfNl8yOTM5ODU3OS0zMjI0Njc0Ny5wbmciKQpgYGAKCmBgYHtyLCBlY2hvID0gRiwgZmlnLmNhcCA9ICIxMjoyNTMzNjE3NC0yNTM4NDA1MyJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJodl8xMl8yNTMzNjE3NC0yNTM4NDA1My5wbmciKQpgYGAKCmBgYHtyLCBlY2hvID0gRiwgZmlnLmNhcCA9ICIxNDoxMjQ5MDg0Mi0xMjk0NzA4MyJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJodl8xNF8xMjQ5MDg0Mi0xMjk0NzA4My5wbmciKQpgYGAKCmBgYHtyLCBlY2hvID0gRiwgZmlnLmNhcCA9ICIxNzoxNTU1Nzg5Mi0xOTU2MTUxOCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJodl8xN18xNTU1Nzg5Mi0xOTU2MTUxOC5wbmciKQpgYGAKCmBgYHtyLCBlY2hvID0gRiwgZmlnLmNhcCA9ICIyMTo2NzEwMDc0LTc4ODAzNzQifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaHZfMjFfNjcxMDA3NC03ODgwMzc0LnBuZyIpCmBgYAoKIyBHZW5vdHlwZSBoZWF0bWFwcyBmb3IgaGlnaC1MRCByZWdpb25zCgpTZWUgd2hpY2ggbGluZXMgYXJlIGNhdXNpbmcgdGhlIGhpZ2gtTEQgcmVnaW9ucyBhdCB0aGUgYE1BRiA+IDAuMDVgIHRocmVzaG9sZCAoaS5lLiBmcm9tIGEgc2FtcGxlIG9mIDYzIGRpcGxvaWQgaW5kaXZpZHVhbHMsIHZhcmlhbnRzIHdpdGggYW4gYWxsZWxlIGNvdW50IChgQUNgKSBvZiBhdCBsZWFzdCBgN2ApLgoKIyMgUmVhZCBkYXRhIGludG8gQkVEIG1hdHJpeCBpbnRvIGBSYAoKYGBge3IsIGV2YWwgPSBGfQojIFJlYWQgaW4gQkVEIG1hdHJpeAptaWtrX2Z1bGwgPC0gZ2FzdG9uOjpyZWFkLmJlZC5tYXRyaXgoaGVyZSgicGxpbmsiLCAiMjAyMDA3MTZfcGFuZWxfbm8tc2lic19saW5lLWlkc19uby1taXNzaW5nLzIwMjAwNzE2IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZHMgPSBOVUxMKQoKIyBSZWFkIGluIGdlbm90eXBlcyBmaWxlCm1pa2tfZ2VubyA8LSByZWFkcjo6cmVhZF90c3YoZmlsZSA9IGhlcmUoInBsaW5rIiwgIjIwMjAwNzE2X3BhbmVsX25vLXNpYnNfbGluZS1pZHNfbm8tbWlzc2luZy8yMDIwMDcxNl9yZWNvZGUwMTIudHJhdyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2dyZXNzID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xfbmFtZXMgPSBUKQoKIyByZW5hbWUgSURzCmNvbG5hbWVzKG1pa2tfZ2VubylbNzpsZW5ndGgoY29sbmFtZXMobWlra19nZW5vKSldIDwtIG1pa2tfZnVsbEBwZWQkaWQKYGBgCgojIyBFeHRyYWN0IHRhcmdldCByZWdpb25zIGFuZCBidWlsZCBpbnRvIGxpc3QKCmBgYHtyLCBldmFsID0gRn0KIyBnZXQgY29vcmRpbmF0ZXMKaGlnaF9sZF9jaHJzIDwtIGMoNSwgNiwgMTIsIDE0LCAxNywgMjEpCmhpZ2hfbGRfc3RhcnQgPC0gYygyODM4NTgwNSwgMjk2MDg1MTQsIDI1MzQwMDAwLCAxMjU4NDYxNCwgMTU1NTk5NjMsIDY4MDAyNjEpCmhpZ2hfbGRfZW5kIDwtIGMoMjg3OTgwNDgsIDMyMjEyMjM1LCAyNTM3Mjk4NSwgMTI4NjExNDcsIDE5NTUzNTI5LCA3NzYwMjU4KQoKIyBidWlsZCBpbnRvIGxpc3QKY291bnRlciA8LSAwCmhpZ2hfbGRfbHN0IDwtIGxhcHBseShoaWdoX2xkX2NocnMsIGZ1bmN0aW9uKHgpewogIGNvdW50ZXIgPDwtIGNvdW50ZXIgKyAxCiAgeCA8LSBsaXN0KCJjaHIiID0geCwKICAgICAgICAgICAgInN0YXJ0IiA9IGhpZ2hfbGRfc3RhcnRbY291bnRlcl0sCiAgICAgICAgICAgICJlbmQiID0gaGlnaF9sZF9lbmRbY291bnRlcl0pCiAgIyBmaW5kIGluZGV4ZXMgZm9yIFNOUHMgd2l0aCBNQUYgPiAwLjA1CiAgeFtbInRhcmdldF9pbmRzIl1dIDwtIHdoaWNoKG1pa2tfZnVsbEBzbnBzJGNociA9PSB4W1siY2hyIl1dICYKICAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjpiZXR3ZWVuKG1pa2tfZnVsbEBzbnBzJHBvcywgeFtbInN0YXJ0Il1dLCB4W1siZW5kIl1dKSAmCiAgICAgICAgICAgICAgICAgICAgICAgICBtaWtrX2Z1bGxAc25wcyRtYWYgPiAwLjA1KQogIHhbWyJ0YXJnZXRfc25wcyJdXSA8LSBtaWtrX2dlbm9beFtbInRhcmdldF9pbmRzIl1dLCBdICAKICAjIG1ha2UgbWF0cml4CiAgeFtbImdlbm9fbWF0Il1dIDwtIGFzLm1hdHJpeCh4W1sidGFyZ2V0X3NucHMiXV1bLCAtKDE6NildKQogIHJldHVybih4KQp9KQpuYW1lcyhoaWdoX2xkX2xzdCkgPC0gaGlnaF9sZF9jaHJzCgojIHNhdmUgdG8gcmVwbwpzYXZlUkRTKGhpZ2hfbGRfbHN0LCBoZXJlOjpoZXJlKCJtaWtrX2dlbm9tZSIsICJkYXRhIiwgIjIwMjAwNzI3X2hpZ2hfbGRfbGlzdC5yZHMiKSkKYGBgCgojIyBQbG90CgpHZW5vdHlwZXMgd2VyZSByZWNvZGVkIHRvIDAsIDEsIDIgZm9yIFJFRiwgSEVULCBhbmQgSE9NX0FMVCByZXNwZWN0aXZlbHkuCgpEYXJrIHJlZCA9IDIKT3JhbmdlID0gMQpZZWxsb3cgPSAwCgpgYGB7ciBsb2FkX2hpZ2hfbGRfbGlzdCwgaW5jbHVkZSA9IEZ9CmhpZ2hfbGRfbHN0ID0gcmVhZFJEUyhoZXJlOjpoZXJlKCJkYXRhIiwgIjIwMjAwNzI3X2hpZ2hfbGRfbGlzdC5yZHMiKSkKYGBgCgpgYGB7cn0KIyBXcml0ZSBmdW5jdGlvbiB0byBjcmVhdGUgaGVhdG1hcApnZXRfaGVhdG1hcCA9IGZ1bmN0aW9uKGluX2xpc3QpewogICMgR2V0IG9yZGVyIG9mIHNhbXBsZXMKICBzYW1wbGVfb3JkZXIgPSBjb2xuYW1lcyhpbl9saXN0W1sidGFyZ2V0X3NucHMiXV0pWy0oMTo2KV0gIAogICMgU29ydCBieSBjb3VudAogIHNvcnRlZF9vcmRlciA9IG5hbWVzKHNvcnQoY29sU3Vtcyhpbl9saXN0W1siZ2Vub19tYXQiXV0pLCBkZWNyZWFzaW5nID0gVCkpCiAgIyBHZXQgcmUtb3JkZXJlZCBpbmRlaW5fbGlzdGVzCiAgbmV3X2luZCA9IG1hdGNoKHNvcnRlZF9vcmRlciwgc2FtcGxlX29yZGVyKQogICMgUGxvdAogIGhlYXRtYXAoaW5fbGlzdFtbImdlbm9fbWF0Il1dWywgbmV3X2luZF0sIAogICAgICAgICAgUm93diA9IE5BLAogICAgICAgICAgQ29sdiA9IE5BLAogICAgICAgICAgc2NhbGUgPSAicm93IiwKICAgICAgICAgIGtlZXAuZGVuZHJvID0gRikgIAp9CmBgYAoKIyMjIENociA1CgpgYGB7ciwgY2FjaGUgPSBULCBmaWcuc2hvdz0iaG9sZCIsIG91dC53aWR0aD0nNTAlJywgIGZpZy5jYXAgPSAiNToyODE4MTk3MC0yODk3MDU1OCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJodl81XzI4MTgxOTcwLTI4OTcwNTU4LnBuZyIpCnggPSBoaWdoX2xkX2xzdFtbIjUiXV0KZ2V0X2hlYXRtYXAoeCkKYGBgCgojIyMgQ2hyIDYKCmBgYHtyLCBjYWNoZSA9IFQsIGZpZy5zaG93PSJob2xkIiwgb3V0LndpZHRoPSc1MCUnLCBmaWcuY2FwID0gIjY6MjkzOTg1NzktMzIyNDY3NDcifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaHZfNl8yOTM5ODU3OS0zMjI0Njc0Ny5wbmciKQp4ID0gaGlnaF9sZF9sc3RbWyI2Il1dCmdldF9oZWF0bWFwKHgpCmBgYAoKIyMjIENociAxMgoKYGBge3IsIGNhY2hlID0gVCwgZmlnLnNob3c9ImhvbGQiLCBvdXQud2lkdGg9JzUwJScsIGZpZy5jYXAgPSAiMTI6MjUzMzYxNzQtMjUzODQwNTMifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaHZfMTJfMjUzMzYxNzQtMjUzODQwNTMucG5nIikKeCA9IGhpZ2hfbGRfbHN0W1siMTIiXV0KZ2V0X2hlYXRtYXAoeCkKYGBgCgojIyMgQ2hyIDE0CgpgYGB7ciwgY2FjaGUgPSBULCBmaWcuc2hvdz0iaG9sZCIsIG91dC53aWR0aD0nNTAlJywgZmlnLmNhcCA9ICIxNDoxMjQ5MDg0Mi0xMjk0NzA4MyJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJodl8xNF8xMjQ5MDg0Mi0xMjk0NzA4My5wbmciKQp4ID0gaGlnaF9sZF9sc3RbWyIxNCJdXQpnZXRfaGVhdG1hcCh4KQpgYGAKCiMjIyBDaHIgMTcKCmBgYHtyLCBjYWNoZSA9IFQsIGZpZy5zaG93PSJob2xkIiwgb3V0LndpZHRoPSc1MCUnLCBmaWcuY2FwID0gIjE3OjE1NTU3ODkyLTE5NTYxNTE4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImh2XzE3XzE1NTU3ODkyLTE5NTYxNTE4LnBuZyIpCnggPSBoaWdoX2xkX2xzdFtbIjE3Il1dCmdldF9oZWF0bWFwKHgpCmBgYAoKIyMjIENociAyMQoKYGBge3IsIGNhY2hlID0gVCwgZmlnLnNob3c9ImhvbGQiLCBvdXQud2lkdGg9JzUwJScsIGZpZy5jYXAgPSAiMjE6NjcxMDA3NC03ODgwMzc0In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImh2XzIxXzY3MTAwNzQtNzg4MDM3NC5wbmciKQp4ID0gaGlnaF9sZF9sc3RbWyIyMSJdXQpnZXRfaGVhdG1hcCh4KQpgYGAKCiMgTEQgZGVjYXkKCldlIHdhbnQgdG8gY29tcGFyZSB0aGUgcmF0ZSBhdCB3aGljaCBMRCBkZWNheXMgd2l0aCBpbnRlci1TTlAgZGlzdGFuY2UgYmV0d2VlbiB0aGUgTUlLSyBwYW5lbCBhbmQgaHVtYW5zLiBUaGlzIHdpbGwgZ2l2ZSBhbiBpbmRpY2F0aW9uIG9mIHRoZSByZXNvbHV0aW9uIGF0IHdoaWNoIG9uZSBjYW4gbWFwIGdlbmV0aWMgdHJhaXRzIHVzaW5nIHRoZSBNSUtLIHBhbmVsLCAqcHJvdmlkZWQgdGhhdCBhdCBsZWFzdCB0d28gbGluZXMgaGF2ZSB0aGUgc2FtZSB2YXJpYW50IG9mIGludGVyZXN0Ki4KCiMjIE9idGFpbiAxMDAwIEdlbm9tZXMgZGF0YXNldAoKIyMjIERvd25sb2FkIGZyb20gRlRQCgpgYGB7YmFzaCwgZXZhbCA9IEZ9CmNkIHZjZnMKCndnZXQgLXIgLXAgLWsgLS1uby1wYXJlbnQgLWN1dC1kaXJzPTUgZnRwOi8vZnRwLjEwMDBnZW5vbWVzLmViaS5hYy51ay92b2wxL2Z0cC9yZWxlYXNlLzIwMTMwNTAyLwpgYGAKCiMjIyBQdXQgbGlzdCBvZiBmaWxlcyBpbnRvIGxpc3QKCmBgYHtiYXNoLCBldmFsID0gRn0KZmluZCB2Y2ZzL2Z0cC4xMDAwZ2Vub21lcy5lYmkuYWMudWsvQUxMLmNocioudmNmLmd6ID4gbWlra19nZW5vbWUvZGF0YS8yMDIwMDIwNV92Y2ZzLmxpc3QKYGBgCgojIyMgTWVyZ2UgVkNGcwoKYGBge2Jhc2gsIGV2YWwgPSBGfQojIFJlbW92ZSBNVCBhbmQgWSBmcm9tIGxpc3QgCnNlZCAtaSAnL01UL2QnIG1pa2tfZ2Vub21lL2RhdGEvMjAyMDAyMDVfdmNmcy5saXN0CgpzZWQgLWkgJy9jaHJZL2QnIG1pa2tfZ2Vub21lL2RhdGEvMjAyMDAyMDVfdmNmcy5saXN0CgojIHJ1biBNZXJnZVZDRnMgCmphdmEgLWphciAvbmZzL3NvZnR3YXJlL2Jpcm5leS9waWNhcmQtMi45LjAvcGljYXJkLmphciBNZXJnZVZjZnMgXAogIEk9bWlra19nZW5vbWUvZGF0YS8yMDIwMDIwNV92Y2ZzLmxpc3QgXAogIE89dmNmcy8xZ2tfYWxsLnZjZi5negpgYGAKCiMjIEdldCBMRCBzdGF0cyB1c2luZyBgUGxpbmtgCgpgYGB7YmFzaCwgZXZhbCA9IEZ9CiMgbWFrZSBCRUQKbWtkaXIgcGxpbmsvMjAyMDA3MjdfbWlra19uby1taXNzaW5nX21hZi0wLjA1CgpwbGluayBcCiAgLS12Y2YgdmNmcy9wYW5lbF9uby1zaWJzX2xpbmUtaWRzLnZjZi5neiBcCiAgLS1tYWtlLWJlZCBcCiAgLS1kb3VibGUtaWQgXAogIC0tc25wcy1vbmx5IFwKICAtLWJpYWxsZWxpYy1vbmx5IFwKICAtLW1hZiAwLjA1IFwKICAtLWdlbm8gMCBcCiAgLS1jaHItc2V0IDI0IG5vLXh5IFwKICAtLW91dCBwbGluay8yMDIwMDcyN19taWtrX25vLW1pc3NpbmdfbWFmLTAuMDUvMjAyMDA3MjcKCiMgZ2V0IExEIHN0YXRzIGZvciBNSUtLCm1rZGlyIGxkLzIwMjAwNzI3X21pa2tfbWFmLTAuMTBfd2luZG93LTUwa2Jfbm8tbWlzc2luZy8KCmZvciBpIGluICQoc2VxIDEgMjQpOyBkbwogIHBsaW5rIFwKICAgICAgLS1iZmlsZSBwbGluay8yMDIwMDcyN19taWtrX25vLW1pc3NpbmdfbWFmLTAuMDUvMjAyMDA3MjcgXAogICAgICAtLXIyIFwKICAgICAgLS1sZC13aW5kb3cgOTk5OTk5IFwKICAgICAgLS1sZC13aW5kb3cta2IgNTAgXAogICAgICAtLWxkLXdpbmRvdy1yMiAwIFwKICAgICAgLS1jaHItc2V0IDI0IG5vLXh5IFwKICAgICAgLS1jaHIgJGkgXAogICAgICAtLW1hZiAwLjEwIFwKICAgICAgLS1vdXQgbGQvMjAyMDA3MjdfbWlra19tYWYtMC4xMF93aW5kb3ctNTBrYl9uby1taXNzaW5nLyRpOwpkb25lCgojIGdldCBMRCBzdGF0cyBmb3IgMUtHCm1rZGlyIGxkLzIwMjAwNzI3XzFrZ19tYWYtMC4xMF93aW5kb3ctNTBrYl9uby1taXNzaW5nLwoKZm9yIGkgaW4gJChzZXEgMSAyMik7IGRvCiAgcGxpbmsgXAogICAgICAtLWJmaWxlIHBsaW5rLzIwMjAwNzIzXzFna19uby1taXNzaW5nX21hZi0wLjA1LzIwMjAwNzIzIFwKICAgICAgLS1yMiBcCiAgICAgIC0tbGQtd2luZG93IDk5OTk5OSBcCiAgICAgIC0tbGQtd2luZG93LWtiIDUwIFwKICAgICAgLS1sZC13aW5kb3ctcjIgMCBcCiAgICAgIC0tY2hyICRpIFwKICAgICAgLS1tYWYgMC4xMCBcCiAgICAgIC0tb3V0IGxkLzIwMjAwNzI3XzFrZ19tYWYtMC4xMF93aW5kb3ctNTBrYl9uby1taXNzaW5nLyRpOwpkb25lCgojIGRvIGFnYWluIHdpdGggbGQtd2luZG93LWtiIDEwIHRvIGdldCBjb3VudHMgb2YgY29tcGFyaXNvbnMgZm9yIHBhcGVyCiMgTUlLSyAgCm1rZGlyIGxkLzIwMjAwODAzX21pa2tfbWFmLTAuMTBfd2luZG93LTEwa2Jfbm8tbWlzc2luZy8KCmZvciBpIGluICQoc2VxIDEgMjQpOyBkbwogIHBsaW5rIFwKICAgICAgLS1iZmlsZSBwbGluay8yMDIwMDcyN19taWtrX25vLW1pc3NpbmdfbWFmLTAuMDUvMjAyMDA3MjcgXAogICAgICAtLXIyIFwKICAgICAgLS1sZC13aW5kb3cgOTk5OTk5IFwKICAgICAgLS1sZC13aW5kb3cta2IgMTAgXAogICAgICAtLWxkLXdpbmRvdy1yMiAwIFwKICAgICAgLS1jaHItc2V0IDI0IG5vLXh5IFwKICAgICAgLS1jaHIgJGkgXAogICAgICAtLW1hZiAwLjEwIFwKICAgICAgLS1vdXQgbGQvMjAyMDA4MDNfbWlra19tYWYtMC4xMF93aW5kb3ctMTBrYl9uby1taXNzaW5nLyRpOwpkb25lCgojIDFLRwpta2RpciBsZC8yMDIwMDgwM18xa2dfbWFmLTAuMTBfd2luZG93LTEwa2Jfbm8tbWlzc2luZy8KCmZvciBpIGluICQoc2VxIDEgMjIpOyBkbwogIHBsaW5rIFwKICAgICAgLS1iZmlsZSBwbGluay8yMDIwMDcyM18xZ2tfbm8tbWlzc2luZ19tYWYtMC4wNS8yMDIwMDcyMyBcCiAgICAgIC0tcjIgXAogICAgICAtLWxkLXdpbmRvdyA5OTk5OTkgXAogICAgICAtLWxkLXdpbmRvdy1rYiAxMCBcCiAgICAgIC0tbGQtd2luZG93LXIyIDAgXAogICAgICAtLWNociAkaSBcCiAgICAgIC0tbWFmIDAuMTAgXAogICAgICAtLW91dCBsZC8yMDIwMDgwM18xa2dfbWFmLTAuMTBfd2luZG93LTEwa2Jfbm8tbWlzc2luZy8kaTsKZG9uZQoKIyBHZXQgdG90YWwgY291bnRzIG9mIHBhaXJ3aXNlIGNvbXBhcmlzb25zOgp3YyAtbCBsZC8yMDIwMDgwM19taWtrX21hZi0wLjEwX3dpbmRvdy0xMGtiX25vLW1pc3NpbmcvKi5sZAojIDIwNCwxNTIsODk4CndjIC1sIGxkLzIwMjAwODAzXzFrZ19tYWYtMC4xMF93aW5kb3ctMTBrYl9uby1taXNzaW5nLyoubGQKYGBgCgojIyBHZXQgbWVhbiBMRCB3aXRoaW4gU05QLWRpc3RhbmNlIHdpbmRvd3MKCiMjIyAwLTEwa2IgZGlzdGFuY2UgKG1haW4sIE1JS0sgdiAxS0cpCgpSc2NyaXB0IGhlcmU6IGBtaWtrX2dlbm9tZS9jb2RlL3NjcmlwdHMvMjAyMDA3MjdfcjJfZGVjYXlfbWVhbl8xMGtiLWxpbS5SYAoKIyMjIyBNSUtLCgpgYGB7YmFzaCwgZXZhbCA9IEZ9CnNjcmlwdD1taWtrX2dlbm9tZS9jb2RlL3NjcmlwdHMvMjAyMDA3MjdfcjJfZGVjYXlfbWVhbl8xMGtiLWxpbS5SCgpta2RpciBsZC8yMDIwMDcyN19tZWFuX3IyXzEwa2ItbGltX21pa2sKCmZvciBpIGluICQoZmluZCBsZC8yMDIwMDcyN19taWtrX21hZi0wLjEwX3dpbmRvdy01MGtiX25vLW1pc3NpbmcvKi5sZCk7IGRvCiAgbmFtZT0kKGJhc2VuYW1lICRpIHwgY3V0IC1mMSAtZCIuIikgOwogIG91dF9kaXI9bGQvMjAyMDA3MjdfbWVhbl9yMl8xMGtiLWxpbV9taWtrIDsKICBic3ViIFwKICAgIC1NIDEwMDAwIFwKICAgIC1vIGxvZy8yMDIwMDcyN18kbmFtZVxfbWVhbi1yMl8xa2ItbWF4Lm91dCBcCiAgICAtZSBsb2cvMjAyMDA3MjdfJG5hbWVcX21lYW4tcjJfMWtiLW1heC5lcnIgXAogICAgIlJzY3JpcHQgLS12YW5pbGxhIFwKICAgICAgJHNjcmlwdCBcCiAgICAgICRpIFwKICAgICAgJG91dF9kaXIiOwpkb25lCmBgYAoKIyMjIyAxS0cKCmBgYHtiYXNoLCBldmFsID0gRn0KbWtkaXIgbGQvMjAyMDA3MjdfbWVhbl9yMl8xMGtiLWxpbV8xa2cKCmZvciBpIGluICQoZmluZCBsZC8yMDIwMDcyN18xa2dfbWFmLTAuMTBfd2luZG93LTUwa2Jfbm8tbWlzc2luZy8qLmxkKTsgZG8KICBuYW1lPSQoYmFzZW5hbWUgJGkgfCBjdXQgLWYxIC1kIi4iKSA7CiAgb3V0X2Rpcj1sZC8yMDIwMDcyN19tZWFuX3IyXzEwa2ItbGltXzFrZyA7CiAgYnN1YiBcCiAgICAtTSAzMDAwMCBcCiAgICAtbyBsb2cvMjAyMDA3MjdfJG5hbWVcX21lYW4tcjJfMTBrYi1tYXgub3V0IFwKICAgIC1lIGxvZy8yMDIwMDcyN18kbmFtZVxfbWVhbi1yMl8xMGtiLW1heC5lcnIgXAogICAgIlJzY3JpcHQgLS12YW5pbGxhIFwKICAgICAgJHNjcmlwdCBcCiAgICAgICRpIFwKICAgICAgJG91dF9kaXIiOwpkb25lCmBgYAoKIyMjIDAtMWtiIGRpc3RhbmNlIChpbnNldCwgTUlLSyBvbmx5KQoKUnNjcmlwdDogYG1pa2tfZ2Vub21lL2NvZGUvc2NyaXB0cy8yMDIwMDgwM19yMl9kZWNheV9tZWFuXzFna18xa2ItbGltLlJgCgpgYGB7YmFzaCwgZXZhbCA9IEZ9Cm1rZGlyIGxkLzIwMjAwODAzX21lYW5fcjJfMWtiLWxpbV9taWtrCgpvdXRfZGlyPWxkLzIwMjAwODAzX21lYW5fcjJfMWtiLWxpbV9taWtrCnNjcmlwdD1taWtrX2dlbm9tZS9jb2RlL3NjcmlwdHMvMjAyMDA4MDNfcjJfZGVjYXlfbWVhbl8xZ2tfMWtiLWxpbS5SCgpmb3IgaSBpbiAkKGZpbmQgbGQvMjAyMDA3MjdfbWlra19tYWYtMC4xMF93aW5kb3ctNTBrYl9uby1taXNzaW5nLypsZCk7IGRvCiAgbmFtZT0kKGJhc2VuYW1lICRpIHwgY3V0IC1mMSAtZCIuIik7CiAgYnN1YiBcCiAgICAtTSAzMDAwMCBcCiAgICAtbyBsb2cvMjAyMDA4MDNfJG5hbWVcX21lYW4tcjJfMWtiLW1heC5vdXQgXAogICAgLWUgbG9nLzIwMjAwODAzXyRuYW1lXF9tZWFuLXIyXzFrYi1tYXguZXJyIFwKICAgICJSc2NyaXB0IC0tdmFuaWxsYSBcCiAgICAgICRzY3JpcHQgXAogICAgICAkaSBcCiAgICAgICRvdXRfZGlyIjsKZG9uZQpgYGAKCiMjIENyZWF0ZSBMRCBwbG90cyBpbiBgUmAKCiMjIyBNYWluCgojIyMjIFJlYWQgaW4gYW5kIHByb2Nlc3MgZGF0YQoKYGBge3IsIGV2YWwgPSBGfQojIFNldHVwCnJlcXVpcmUoaGVyZSkKc291cmNlKGhlcmUoIm1pa2tfZ2Vub21lIiwgImNvZGUiLCAic2NyaXB0cyIsICJzZXR1cC5SIikpCgojIENyZWF0ZSBmdW5jdGlvbiB0byByZWFkIGluIGRhdGEgYW5kIGJpbmQgaW50byBzaW5nbGUgREYKCnJlYWRfbl9iaW5kID0gZnVuY3Rpb24oZGF0YV9wYXRoX3ByZWYsIGRhdGFzZXQpewogICMgU2V0IHBhdGgKICBwYXRoID0gcGFzdGUoZGF0YV9wYXRoX3ByZWYsIGRhdGFzZXQsIHNlcCA9ICIiKQogIAogICMgUmVhZCBpbiBkYXRhCiAgZGF0YV9maWxlcyA8LSBsaXN0LmZpbGVzKHBhdGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bGwubmFtZXMgPSBUKQogIGRhdGFfZmlsZXNfdHJ1bmMgPC0gbGlzdC5maWxlcyhwYXRoKQogIGRhdGFfZmlsZXNfdHJ1bmMgPC0gZ3N1YigiLnR4dCIsICIiLCBkYXRhX2ZpbGVzX3RydW5jKQogIAogIGRhdGFfbGlzdCA8LSBsYXBwbHkoZGF0YV9maWxlcywgZnVuY3Rpb24oZGF0YV9maWxlKXsKICAgIGRmIDwtIHJlYWQuZGVsaW0oZGF0YV9maWxlLAogICAgICAgICAgICAgICAgICAgICBzZXAgPSAiXHQiLAogICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBUKQogICAgcmV0dXJuKGRmKQogIH0pCiAgbmFtZXMoZGF0YV9saXN0KSA8LSBhcy5pbnRlZ2VyKGRhdGFfZmlsZXNfdHJ1bmMpCiAgCiAgIyByZW9yZGVyCiAgZGF0YV9saXN0IDwtIGRhdGFfbGlzdFtvcmRlcihhcy5pbnRlZ2VyKG5hbWVzKGRhdGFfbGlzdCkpKV0KICAKICAjIGJpbmQgaW50byBERgogIG91dF9kZiA9IGRwbHlyOjpiaW5kX3Jvd3MoZGF0YV9saXN0LCAuaWQgPSAiY2hyIikKICBvdXRfZGYkY2hyIDwtIGZhY3RvcihvdXRfZGYkY2hyLCBsZXZlbHMgPSBzZXEoMSwgMjQpKQogIAogICMgZ2V0IGtiIG1lYXN1cmUKICBvdXRfZGYkYmluX2Jkcl9rYiA8LSBvdXRfZGYkYmluX2JkciAvIDEwMDAgIAogIAogIHJldHVybihvdXRfZGYpCn0KCiMgUnVuIG92ZXIgYm90aCBkYXRhc2V0cwpkYXRhc2V0cyA9IGMoIm1pa2siLCAiMWtnIikKZmluYWxfbHN0ID0gbGFwcGx5KGRhdGFzZXRzLCBmdW5jdGlvbih4KSByZWFkX25fYmluZCgibGQvMjAyMDA3MjdfbWVhbl9yMl8xMGtiLWxpbV8iLCB4KSkKbmFtZXMoZmluYWxfbHN0KSA9IGRhdGFzZXRzCgojIENvbWJpbmUgaW50byBzaW5nbGUgREYKcjJfZmluYWxfZGYgPC0gZHBseXI6OmJpbmRfcm93cyhmaW5hbF9sc3QsIC5pZCA9ICJkYXRhc2V0IikKYGBgCgpgYGB7ciwgZXZhbCA9IEZ9CiMgV3JpdGUgdGFibGUgdG8gcmVwbwp3cml0ZS50YWJsZShyMl9maW5hbF9kZiwKICAgICAgICAgICAgZmlsZSA9IGhlcmU6OmhlcmUoIm1pa2tfZ2Vub21lIiwgImRhdGEiLCAiMjAyMDA4MDNfcjJfMTBrYi1saW0uY3N2IiksCiAgICAgICAgICAgIHF1b3RlID0gRiwgc2VwID0gIiwiLCByb3cubmFtZXMgPSBGLCBjb2wubmFtZXMgPSBUKQpgYGAKCiMjIyMgUGxvdAoKYGBge3IsIGluY2x1ZGUgPSBGfQpyMl9maW5hbF9kZiA9IHJlYWQudGFibGUoaGVyZSgiZGF0YSIsICIyMDIwMDgwM19yMl8xMGtiLWxpbS5jc3YiKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiLCIpCmBgYAoKYGBge3J9CiMgVGlkeSBkYXRhIGZvciBmaW5hbCBwbG90CnIyX2ZpbmFsX2RmJGNociA9IGZhY3RvcihyMl9maW5hbF9kZiRjaHIsIGxldmVscyA9IHNlcSgxLCAyNCkpCnIyX2ZpbmFsX2RmJGRhdGFzZXQgPSB0b3VwcGVyKHIyX2ZpbmFsX2RmJGRhdGFzZXQpCgojIFBsb3QKcjJfcGxvdF9tYWluID0gcjJfZmluYWxfZGYgJT4lIGdncGxvdCgpICsKICBnZW9tX2xpbmUoYWVzKGJpbl9iZHJfa2IsIG1lYW4sIGNvbG91ciA9IGNocikpICsKICB0aGVtZV9jb3dwbG90KCkgKwogIHhsYWIoIkRpc3RhbmNlIGJldHdlZW4gU05QcyAoa2IpIikgKwogIHlsYWIoYnF1b3RlKC4oIk1lYW4gciIpXjIpKSArCiAgZmFjZXRfd3JhcCh+ZGF0YXNldCwgbnJvdyA9IDEsIG5jb2wgPSAyKSArCiAgdGhlbWUocGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC45LCAuOCkpICsKICBsYWJzKGNvbG91ciA9ICJDaHJvbW9zb21lIikgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBjKDAuMSwgMC4yLCAwLjMsIDAuNCwgMC41LCAwLjYpLAogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDAuMDUsIDAuNikpCgojcjJfcGxvdF9tYWluCmBgYAoKYGBge3J9CmdncGxvdGx5KHIyX3Bsb3RfbWFpbikKYGBgCgoKYGBge3IsIGV2YWwgPSBGfQojIFNhdmUgcGxvdCB0byByZXBvCmdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlKCIyMDIwMDgwM19tZWFuLXIyXzEwa2ItbGltXzFLR3ZNSUtLX3NpbmdsZSIsICIuc3ZnIiwgc2VwID0gIiIpLAogICAgICAgcGxvdCA9IHIyX3Bsb3RfbWFpbiwKICAgICAgIGRldmljZSA9ICJzdmciLAogICAgICAgcGF0aCA9IGhlcmU6OmhlcmUoInBsb3RzIiwgImxkX2RlY2F5IiksCiAgICAgICB3aWR0aCA9IDI1LAogICAgICAgaGVpZ2h0ID0gMTMsCiAgICAgICB1bml0cyA9ICJjbSIpCmBgYAoKIyMjIEluc2V0CgojIyMjIDEwMC1icCB3aW5kb3dzCgpgYGB7ciwgZXZhbCA9IEZ9CiMgUmVhZCBpbiBkYXRhCnIyX2RmXzFrYl9taWtrID0gcmVhZF9uX2JpbmQoImxkLzIwMjAwODAzX21lYW5fcjJfMWtiLWxpbV8iLCAibWlrayIpCgpgYGAKCmBgYHtyLCBldmFsID0gRn0KIyBXcml0ZSB0YWJsZSB0byByZXBvCndyaXRlLnRhYmxlKHIyX2RmXzFrYl9taWtrLAogICAgICAgICAgICBmaWxlID0gaGVyZTo6aGVyZSgibWlra19nZW5vbWUiLCAiZGF0YSIsICIyMDIwMDgwM19yMl8xa2ItbGltX21pa2suY3N2IiksCiAgICAgICAgICAgIHF1b3RlID0gRiwgc2VwID0gIiwiLCByb3cubmFtZXMgPSBGLCBjb2wubmFtZXMgPSBUKQpgYGAKCmBgYHtyLCBpbmNsdWRlID0gRn0KcjJfZGZfMWtiX21pa2sgPSByZWFkLnRhYmxlKGhlcmU6OmhlcmUoImRhdGEiLCAiMjAyMDA4MDNfcjJfMWtiLWxpbV9taWtrLmNzdiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICIsIikKYGBgCgpgYGB7cn0KIyBQcm9jZXNzIGZvciBwbG90dGluZwpyMl9kZl8xa2JfbWlrayRjaHIgPC0gZmFjdG9yKHIyX2RmXzFrYl9taWtrJGNociwgbGV2ZWxzID0gc2VxKDEsIDI0KSkKCiMgUGxvdApyMl8xa2JfbWlrayA9IHIyX2RmXzFrYl9taWtrICU+JSBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGFlcyhiaW5fYmRyLCBtZWFuLCBjb2xvdXIgPSBjaHIpKSArCiAgdGhlbWVfYncoKSArCiAgeGxhYigiRGlzdGFuY2UgYmVldHdlZW4gU05QcyAoYnApIikgKwogIHlsYWIoYnF1b3RlKC4oIk1lYW4gciIpXjIpKSArCiAgbGFicyhjb2xvdXIgPSAiQ2hyb21vc29tZSIpICsKICB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSkgKwogIGd1aWRlcyhjb2xvdXIgPSBGKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMTAwMCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gYygwLjEsIDAuMiwgMC4zLCAwLjQsIDAuNSwgMC42KSwKICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLjA1LCAwLjYpKQoKcjJfMWtiX21pa2sKYGBgCgpgYGB7ciwgZXZhbCA9IEZ9CiMgU2F2ZSB0byByZXBvCmdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlKCIyMDIwMDgwM19tZWFuLXIyXzFrYi1saW1fTUlLS19pbnNldF8xMDBicC1iaW5zIiwgIi5wbmciLCBzZXAgPSAiIiksCiAgICAgICBwbG90ID0gcjJfMWtiX21pa2ssCiAgICAgICBkZXZpY2UgPSAicG5nIiwKICAgICAgIHBhdGggPSBoZXJlOjpoZXJlKCJtaWtrX2dlbm9tZSIsICJwbG90cyIpLAogICAgICAgd2lkdGggPSAxMC44OCwKICAgICAgIGhlaWdodCA9IDgsCiAgICAgICB1bml0cyA9ICJjbSIsCiAgICAgICBkcGkgPSA1MDApCmBgYAoKIyMjIyAxMC1icCB3aW5kb3dzCgpGb3IgYSBmaW5lciByZXNvbHV0aW9uLgoKIyMjIyMgR2V0IG1lYW5zIGZvciBlYWNoIGJpbgoKYGBge2Jhc2gsIGV2YWwgPSBGfQpzY3JpcHQ9bWlra19nZW5vbWUvY29kZS9zY3JpcHRzLzIwMjAwNzI0X3IyX2RlY2F5X21lYW5fMWdrXzFrYi1saW0uUgpvdXRfZGlyPWxkLzIwMjAwNzI3X21lYW5fcjJfMWtiLWxpbV9taWtrCgpmb3IgaW5fZmlsZSBpbiAkKGZpbmQgbGQvMjAyMDA3MjdfbWlra19tYWYtMC4xMF93aW5kb3ctNTBrYl9uby1taXNzaW5nLypsZCk7IGRvCiAgbmFtZT0kKGJhc2VuYW1lICRpbl9maWxlIHwgY3V0IC1mMSAtZCIuIik7CiAgYnN1YiBcCiAgICAtTSAzMDAwMCBcCiAgICAtbyBsb2cvMjAyMDA4MDNfJG5hbWVcX21lYW4tcjJfMWtiLW1heC5vdXQgXAogICAgLWUgbG9nLzIwMjAwODAzXyRuYW1lXF9tZWFuLXIyXzFrYi1tYXguZXJyIFwKICAgICJSc2NyaXB0IFwKICAgICAgLS12YW5pbGxhIFwKICAgICAgJHNjcmlwdCBcCiAgICAgICRpbl9maWxlIFwKICAgICAgJG91dF9kaXIiOwpkb25lCmBgYAoKYGBge3IsIGV2YWwgPSBGfQojIENvbWJpbmUgaW4gUgpkYXRhX2ZpbGVzIDwtIGxpc3QuZmlsZXMoImxkLzIwMjAwNzI3X21lYW5fcjJfMWtiLWxpbV9taWtrIiwKICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bGwubmFtZXMgPSBUKQoKZGF0YV9maWxlc190cnVuYyA8LSBsaXN0LmZpbGVzKCJsZC8yMDIwMDcyN19tZWFuX3IyXzFrYi1saW1fbWlrayIpCgpkYXRhX2ZpbGVzX3RydW5jIDwtIGdzdWIoIi50eHQiLCAiIiwgZGF0YV9maWxlc190cnVuYykKCmRhdGFfbGlzdCA8LSBsYXBwbHkoZGF0YV9maWxlcywgZnVuY3Rpb24oZGF0YV9maWxlKXsKICBkZiA8LSByZWFkLmRlbGltKGRhdGFfZmlsZSwKICAgICAgICAgICAgICAgICAgIHNlcCA9ICJcdCIsCiAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBUKQogIHJldHVybihkZikKfSkKCm5hbWVzKGRhdGFfbGlzdCkgPC0gYXMuaW50ZWdlcihkYXRhX2ZpbGVzX3RydW5jKQoKIyByZW9yZGVyCmRhdGFfbGlzdCA8LSBkYXRhX2xpc3Rbb3JkZXIoYXMuaW50ZWdlcihuYW1lcyhkYXRhX2xpc3QpKSldCgojIGJpbmQgaW50byBERgpyMl9kZl8xa2JfbWlrayA8LSBkcGx5cjo6YmluZF9yb3dzKGRhdGFfbGlzdCwgLmlkID0gImNociIpCnIyX2RmXzFrYl9taWtrJGNociA8LSBmYWN0b3IocjJfZGZfMWtiX21pa2skY2hyLCBsZXZlbHMgPSBzZXEoMSwgMjQpKQoKIyB3cml0ZSB0byB0YWJsZQp3cml0ZS50YWJsZShyMl9kZl8xa2JfbWlraywgaGVyZTo6aGVyZSgibWlra19nZW5vbWUiLCAiZGF0YSIsICIyMDIwMDgwM19taWtrX2xkLWRlY2F5XzFrYi1saW1fMTBicC13aW5kb3dzLnR4dCIpLAogICAgICAgICAgICBxdW90ZSA9IEYsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IFQsIHNlcCA9ICJcdCIpCmBgYAoKIyMjIyMgUGxvdAoKYGBge3J9CiMgUmVhZCBpbiBkYXRhCnIyX2RmXzFrYl9taWtrID0gcmVhZC50YWJsZShoZXJlOjpoZXJlKCJkYXRhIiwgIjIwMjAwODAzX21pa2tfbGQtZGVjYXlfMWtiLWxpbV8xMGJwLXdpbmRvd3MudHh0IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBULCBzZXAgPSAiXHQiLCBhcy5pcyA9IFQpCgoKIyBGYWN0b3Jpc2UgY2hyb21vc29tZXMKcjJfZGZfMWtiX21pa2skY2hyIDwtIGZhY3RvcihyMl9kZl8xa2JfbWlrayRjaHIsIGxldmVscyA9IHNlcSgxLCAyNCkpCgojIFBsb3QKcjJfZGZfMWtiX21pa2sgJT4lIGdncGxvdCgpICsKICBnZW9tX2xpbmUoYWVzKGJpbl9iZHIsIG1lYW4sIGNvbG91ciA9IGNocikpICsKICB0aGVtZV9idygpICsKICB4bGFiKCJEaXN0YW5jZSBiZWV0d2VlbiBTTlBzIChicCkiKSArCiAgeWxhYihicXVvdGUoLigiTWVhbiByIileMikpICsKICBsYWJzKGNvbG91ciA9ICJDaHJvbW9zb21lIikgKwogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpKSArCiAgZ3VpZGVzKGNvbG91ciA9IEYpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gYygwLjEsIDAuMiwgMC4zLCAwLjQsIDAuNSwgMC42LCAwLjcpLAogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDAuMDUsIDAuNykpCgpgYGAKCmBgYHtyLCBldmFsID0gRn0KIyBTYXZlCmdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlKCIyMDIwMDgwM19tZWFuLXIyXzFrYi1saW1fTUlLS19pbnNldF8xMGJwLXdpbmRvd3MiLCAiLnBuZyIsIHNlcCA9ICIiKSwKICAgICAgIGRldmljZSA9ICJwbmciLAogICAgICAgcGF0aCA9IGhlcmU6OmhlcmUoIm1pa2tfZ2Vub21lIiwgInBsb3RzIiksCiAgICAgICB3aWR0aCA9IDEwLjg4LAogICAgICAgaGVpZ2h0ID0gOCwKICAgICAgIHVuaXRzID0gImNtIiwKICAgICAgIGRwaSA9IDUwMCkKYGBgCgojIE1BRiBkaXN0cmlidXRpb24gTUlLSyB2IDFLRwoKIyMgR2V0IGZyZXF1ZW5jaWVzIHdpdGggYHBsaW5rYAoKYGBge2Jhc2gsIGV2YWwgPSBGfQojIDFLRwpwbGluayBcCiAgLS1iZmlsZSBwbGluay8yMDIwMDcyM18xZ2tfbm8tbWlzc2luZy8yMDIwMDcyMyBcCiAgLS1mcmVxIFwKICAtLW91dCBtYWYvMjAyMDA3MjdfMWtnX25vLW1pc3NpbmcKIyBDcmVhdGVzIGEgMy45R0IgZmlsZS4gIAogIAojIE1JS0sKcGxpbmsgXAogIC0tYmZpbGUgcGxpbmsvMjAyMDA3MTZfcGFuZWxfbm8tc2lic19saW5lLWlkc19uby1taXNzaW5nLzIwMjAwNzE2IFwKICAtLWZyZXEgXAogIC0tY2hyLXNldCAyNCBuby14eSBcCiAgLS1vdXQgbWFmLzIwMjAwNzI3X21pa2tfbm8tbWlzc2luZwojIENyZWF0ZXMgYSA2NTdNQiBmaWxlLiAKYGBgCgojIyBQbG90CgpgYGB7ciwgZXZhbCA9IEZ9CmluX21pa2sgPC0gIi4uL21hZi8yMDIwMDcyN19taWtrX25vLW1pc3NpbmcuZnJxIgppbl8xa2cgPC0gIi4uL21hZi8yMDIwMDcyN18xa2dfbm8tbWlzc2luZy5mcnEiCiNvdXRfZmlsZSA8LSBhcmdzWzNdCgojIyBNSUtLCm1hZl9taWtrIDwtIHJlYWRyOjpyZWFkX2RlbGltKGluX21pa2ssCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVsaW0gPSAiICIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJpbV93cyA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sX3R5cGVzID0gY29sc19vbmx5KE1BRiA9IGNvbF9kb3VibGUoKSkpCm1hZl9taWtrJGRhdGFzZXQgPC0gIk1JS0siCgojIyAxS0cKbWFmXzFrZyA8LSByZWFkcjo6cmVhZF9kZWxpbShpbl8xa2csCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVsaW0gPSAiICIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJpbV93cyA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sX3R5cGVzID0gY29sc19vbmx5KE1BRiA9IGNvbF9kb3VibGUoKSkpCm1hZl8xa2ckZGF0YXNldCA8LSAiMUtHIgoKIyMgQmluZAptYWZfZmluYWwgPC0gcmJpbmQobWFmX21pa2ssIG1hZl8xa2cpCgojIFBsb3QKbWFmX3Bsb3QgPSBtYWZfZmluYWwgJT4lCiAgZ2dwbG90KCkgKwogICAgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBNQUYsCiAgICAgICAgICAgICAgICAgICAgICAgeT0wLjAxKi4uZGVuc2l0eS4uLAogICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBkYXRhc2V0KSwKICAgICAgICAgICAgICAgICAgIGJpbndpZHRoID0gMC4wMSkgKwogICAgdGhlbWVfY293cGxvdCgpICsKICAgIGd1aWRlcyhmaWxsID0gRikgKwogICAgZmFjZXRfd3JhcCh+ZGF0YXNldCwgbnJvdyA9IDEsIG5jb2wgPSAyKSArCiAgICB4bGFiKCJNaW5vciBhbGxlbGUgZnJlcXVlbmNpZXMiKSArCiAgICB5bGFiKCJEZW5zaXR5IikgKwogICAgdGhlbWUoc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlID0gImJvbGQiKSkKYGBgCgojIyMgTEQgZGVjYXkgd2l0aG91dCBsYWJlbHMKCmBgYHtyLCBldmFsID0gRn0KcjJfcGxvdF9tYWluX25vbGFicyA9IHIyX2ZpbmFsX2RmICU+JSBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGFlcyhiaW5fYmRyX2tiLCBtZWFuLCBjb2xvdXIgPSBjaHIpKSArCiAgdGhlbWVfY293cGxvdCgpICsKICB4bGFiKCJEaXN0YW5jZSBiZXR3ZWVuIFNOUHMgKGtiKSIpICsKICB5bGFiKGJxdW90ZSguKCJNZWFuIHIiKV4yKSkgKwogIGZhY2V0X3dyYXAofmRhdGFzZXQsIG5yb3cgPSAxLCBuY29sID0gMikgKwogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gYyguOSwgLjgpLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoOSwgInBvaW50cyIpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpKSArCiAgbGFicyhjb2xvdXIgPSAiQ2hyb21vc29tZSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gYygwLjEsIDAuMiwgMC4zLCAwLjQsIDAuNSwgMC42KSwKICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLjA1LCAwLjYpKQpgYGAKCiMjIENvbWJpbmUgd2l0aCBMRCBkZWNheSBmb3IgZmluYWwgZmlndXJlCgpgYGB7ciwgZXZhbCA9IEZ9CmZpbmFsX2ZpZyA9IGNvd3Bsb3Q6OmdnZHJhdygpICsKICBkcmF3X3Bsb3QobWFmX3Bsb3QsCiAgICAgICAgICAgIHggPSAwLCB5ID0gLjcsIHdpZHRoID0gMSwgaGVpZ2h0ID0gLjMpICsKICBkcmF3X3Bsb3QocjJfcGxvdF9tYWluX25vbGFicywKICAgICAgICAgICAgeCA9IDAsIHkgPSAwLCB3aWR0aCA9IDEsIGhlaWdodCA9IC43KSArCiAgZHJhd19wbG90X2xhYmVsKGxhYmVsID0gYygiQSIsICJCIiksIHNpemUgPSAxNSwKICAgICAgICAgICAgICAgICAgeCA9IGMoMCwgMCksIHkgPSBjKDEsIC43KSkKYGBgCgoKYGBge3IsIGV2YWwgPSBGfQpvdXRfcGF0aCA9IGhlcmU6OmhlcmUoInBsb3RzIiwgImxkX2RlY2F5IiwgIjIwMjEwMzA1X2ZpbmFsX2ZpZ3VyZS5wbmciKQoKZ2dzYXZlKG91dF9wYXRoLAogICAgICAgcGxvdCA9IGZpbmFsX2ZpZywKICAgICAgIGRldmljZSA9ICJwbmciLAogICAgICAgd2lkdGggPSAyMywKICAgICAgIGhlaWdodCA9IDIyLAogICAgICAgdW5pdHMgPSAiY20iLAogICAgICAgZHBpID0gNTAwKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJwbG90cyIsICJsZF9kZWNheSIsICIyMDIxMDMwNV9maW5hbF9maWd1cmUucG5nIikpCmBgYAoKIyBJbnZlc3RpZ2F0aW9uIG9mIExEIGRlY2F5IGluIGNociAyCgpDaHJvbXNvbWUgMiBoYXMgYW4gb2J2aW91c2x5IGZhc3RlciBMRCBkZWNheSB0aGFuIHRoZSBvdGhlciBjaHJvbW9zb21lcy4gV2UgZXhwbG9yZSBzb21lIHBvc3NpYmxlIHJlYXNvbnMgZm9yIHRoaXMuCgojIyBHZXQgbGVuZ3RocyBvZiBlYWNoIGNociBvbiBgYmFzaGAKYGBge2Jhc2gsIGV2YWwgPSBGfQpzZXEgMSAyNCA+IHRtcDEudHh0CgpncmVwICI+IiByZWZzL09yeXppYXNfbGF0aXBlcy5BU00yMjM0Njd2MS5kbmEudG9wbGV2ZWwuZmEgfCBzY3V0IC1mNiAtZCI6IiB8IGhlYWQgLTI0ID4gdG1wMi50eHQKCnBhc3RlIHRtcDEudHh0IHRtcDIudHh0ID4gbWlra19nZW5vbWUvZGF0YS9Pcnl6aWFzX2xhdGlwZXMuQVNNMjIzNDY3djEuZG5hLnRvcGxldmVsLmZhX2Nocl9jb3VudHMudHh0CmBgYAoKIyMgR2V0IHByb3BvcnRpb24gb2YgZWFjaCBjaHJvbW9zb21lIGNvdmVyZWQgYnkgZXhvbnMgdXNpbmcgYGJpb21hUnRgCgpgYGB7ciwgbWVzc2FnZSA9IEYsIHdhcm5pbmcgPSBGfQojIExvYWQgbGlicmFyaWVzCmxpYnJhcnkoaGVyZSkKc291cmNlKGhlcmU6OmhlcmUoImNvZGUiLCAic2NyaXB0cyIsICJzZXR1cC5SIikpCgojIEdldCBsZW5ndGggb2YgY2hyb21vc29tZXMKY2hyX2NvdW50cyA8LSByZWFkcjo6cmVhZF90c3YoaGVyZTo6aGVyZSgiZGF0YSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9yeXppYXNfbGF0aXBlcy5BU00yMjM0Njd2MS5kbmEudG9wbGV2ZWwuZmFfY2hyX2NvdW50cy50eHQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sX25hbWVzID0gYygiY2hyIiwgImxlbmd0aCIpKQoKIyBMaXN0IG1hcnRzIApsaXN0TWFydHMoKQoKIyBTZWxlY3QgZGF0YWJhc2UgYW5kIGxpc3QgZGF0YXNldHMgd2l0aGluCmVuc2VtYmxfbWFydCA8LSB1c2VNYXJ0KCJFTlNFTUJMX01BUlRfRU5TRU1CTCIpCgojIFNlbGVjdCBkYXRhc2V0CmVuc2VtYmxfb2xhdCA8LSB1c2VEYXRhc2V0KCJvbGF0aXBlc19nZW5lX2Vuc2VtYmwiLCBtYXJ0ID0gZW5zZW1ibF9tYXJ0KQpvbGF0X21hcnQgPSB1c2VFbnNlbWJsKGJpb21hcnQgPSAiZW5zZW1ibCIsIGRhdGFzZXQgPSAib2xhdGlwZXNfZ2VuZV9lbnNlbWJsIikKIyBHZXQgYXR0cmlidXRlcyBvZiBpbnRlcmVzdCAoZXhvbiBJRCwgY2hyLCBzdGFydCwgZW5kKQpleG9ucyA8LSBnZXRCTShhdHRyaWJ1dGVzID0gYygiY2hyb21vc29tZV9uYW1lIiwgImVuc2VtYmxfZ2VuZV9pZCIsICJlbnNlbWJsX3RyYW5zY3JpcHRfaWQiLCAidHJhbnNjcmlwdF9zdGFydCIsICJ0cmFuc2NyaXB0X2VuZCIsICJ0cmFuc2NyaXB0X2xlbmd0aCIsICJlbnNlbWJsX2V4b25faWQiLCAicmFuayIsICJzdHJhbmQiLCAiZXhvbl9jaHJvbV9zdGFydCIsICJleG9uX2Nocm9tX2VuZCIsICJjZHNfc3RhcnQiLCAiY2RzX2VuZCIpLAogICAgICAgICAgICAgICBtYXJ0ID0gb2xhdF9tYXJ0KQoKIyBGYWN0b3Jpc2UgY2hyIHNvIGl0J3MgaW4gdGhlIHJpZ2h0IG9yZGVyCmNocnMgPC0gdW5pcXVlKGV4b25zJGNocm9tb3NvbWVfbmFtZSkKYXV0b19yYW5nZSA8LSByYW5nZShhcy5pbnRlZ2VyKGNocnMpLCBuYS5ybSA9IFQpCm5vbl9hdXRvIDwtIGNocnNbaXMubmEoYXMuaW50ZWdlcihjaHJzKSldCmNocl9vcmRlciA8LSBjKHNlcShhdXRvX3JhbmdlWzFdLCBhdXRvX3JhbmdlWzJdKSwgbm9uX2F1dG8pCmV4b25zJGNocm9tb3NvbWVfbmFtZSA8LSBmYWN0b3IoZXhvbnMkY2hyb21vc29tZV9uYW1lLCBsZXZlbHMgPSBjaHJfb3JkZXIpCgojIENvbnZlcnQgaW50byBsaXN0CmV4b25zX2xzdCA8LSBzcGxpdChleG9ucywgZiA9IGV4b25zJGNocm9tb3NvbWVfbmFtZSkKCiMgR2V0IG1lYW4gbGVuZ3RoIG9mIGV4b25zIHBlciBjaHJvbW9zb21lCmV4b25zX2xzdCA8LSBsYXBwbHkoZXhvbnNfbHN0LCBmdW5jdGlvbihjaHIpewogIGNociA8LSBjaHIgJT4lCiAgICBkcGx5cjo6bXV0YXRlKGV4b25fbGVuZ3RoID0gKGV4b25fY2hyb21fZW5kIC0gZXhvbl9jaHJvbV9zdGFydCkgKyAxLAogICAgICAgICAgICAgICAgICB0cmFuc2NyaXB0X3RvdGFsX2xlbmd0aCA9ICh0cmFuc2NyaXB0X2VuZCAtIHRyYW5zY3JpcHRfc3RhcnQpICsgMSkKICByZXR1cm4oY2hyKQp9KQoKIyBHZXQgdG90YWwgbGVuZ3RoIG9mIGNociBjb3ZlcmVkIGJ5IGV4b25zCmV4b25fbGVuZ3RocyA8LSBsYXBwbHkoZXhvbnNfbHN0LCBmdW5jdGlvbihjaHIpewogICMgY3JlYXRlIGxpc3Qgb2Ygc3RhcnQgcG9zIHRvIGVuZCBwb3Mgc2VxdWVuY2VzIGZvciBlYWNoIGV4b24KICBvdXRfbGlzdCA8LSBhcHBseShjaHIsIDEsIGZ1bmN0aW9uKGV4b24pIHsKICAgIHNlcShleG9uW1siZXhvbl9jaHJvbV9zdGFydCJdXSwgZXhvbltbImV4b25fY2hyb21fZW5kIl1dKQogIH0pCiAgIyBjb21iaW5lIGxpc3Qgb2YgdmVjdG9ycyBpbnRvIHNpbmdsZSB2ZWN0b3IgYW5kIGdldCBvbmx5IHVuaXF1ZSBudW1iZXJzCiAgb3V0X3ZlYyA8LSB1bmlxdWUodW5saXN0KG91dF9saXN0KSkKICAjIGdldCBsZW5ndGggb2Ygb3V0X3ZlYyBhbmQgcHV0IGl0IGludG8gZGF0YSBmcmFtZQogIG91dF9maW5hbCA8LSBkYXRhLmZyYW1lKCJleG9uX2NvdiIgPSBsZW5ndGgob3V0X3ZlYykpCiAgcmV0dXJuKG91dF9maW5hbCkKfSkKCiMgY29tYmluZSBpbnRvIHNpbmdsZSBERgpleG9uc19sZW5fZGYgPC0gZHBseXI6OmJpbmRfcm93cyhleG9uX2xlbmd0aHMsIC5pZCA9ICJjaHIiKSAlPiUgCiAgZHBseXI6OmZpbHRlcihjaHIgIT0gIk1UIikgJT4lIAogIGRwbHlyOjptdXRhdGUoY2hyID0gYXMuaW50ZWdlcihjaHIpKQoKIyBqb2luIHdpdGggY2hyX2NvdW50cyBhbmQgZ2V0IHByb3BvcnRpb24gb2YgY2hyIGNvdmVyZWQgYnkgZXhvbnMKY2hyX3N0YXRzIDwtIGRwbHlyOjpsZWZ0X2pvaW4oY2hyX2NvdW50cywgZXhvbnNfbGVuX2RmLCBieSA9ICJjaHIiKSAlPiUgCiAgZHBseXI6Om11dGF0ZShwcm9wX2Nvdl9leG9uID0gZXhvbl9jb3YgLyBsZW5ndGgpCiMgY29udmVydCBjaHIgdG8gZmFjdG9yIGZvciBwbG90dGluZwpjaHJfc3RhdHMkY2hyIDwtIGZhY3RvcihjaHJfc3RhdHMkY2hyKQpgYGAKCiMjIEdldCBTTlAgY291bnRzIHBlciBtZWdhYmFzZQoKIyMjIEdldCBjb3VudHMKCmBgYHtiYXNoLCBldmFsID0gRn0KYmNmdG9vbHMgaW5kZXggXAogIC0tc3RhdHMgXAogIC4uL3ZjZnMvcGFuZWxfbm8tc2lic19saW5lLWlkc19uby1taXNzaW5nX2JpLXNucHNfd2l0aC1hZi52Y2YuZ3ogXAogICAgPiBkYXRhLzIwMjAxMTA2X25vbi1taXNzaW5nX2JpLXNucF9jb3VudC50eHQKYGBgCgojIyMgUmVhZCBTTlAgY291bnRzIGRhdGEgaW50byBgUmAKCmBgYHtyfQpzbnBfY291bnRzID0gcmVhZC50YWJsZShoZXJlOjpoZXJlKCJkYXRhIiwgIjIwMjAxMTA2X25vbi1taXNzaW5nX2JpLXNucF9jb3VudC50eHQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwKICAgICAgICAgICAgICAgICAgICAgICAgY29sLm5hbWVzID0gYygiY2hyIiwgImxlbmd0aCIsICJzbnBfY291bnQiKSkgJT4lIAogICMgY3JlYXRlIG1lZ2FiYXNlIGNvbHVtbgogIGRwbHlyOjptdXRhdGUobWVnYWJhc2VzID0gbGVuZ3RoIC8gMWU2LAogICAgICAgICAgICAgICAgc25wc19wZXJfbWVnYWJhc2UgPSBzbnBfY291bnQgLyBtZWdhYmFzZXMpICU+JSAKICAjIHJlbW92ZSBNVAogIGRwbHlyOjpmaWx0ZXIoY2hyICE9ICJNVCIpICU+JSAKICAjIHR1cm4gY2hyIGNvbHVtbiBpbnRvIGludGVnZXIKICBkcGx5cjo6bXV0YXRlKGNociA9IGFzLmZhY3Rvcihhcy5pbnRlZ2VyKGNocikpKQpgYGAKCgojIyBDb21iaW5lIFNOUCBjb3VudHMgd2l0aCBleG9uIHByb3BvcnRpb24gY291bnRzCgpgYGB7cn0KY2hyX2RmID0gc25wX2NvdW50cyAlPiUgCiAgZHBseXI6OmZ1bGxfam9pbihjaHJfc3RhdHMsIGJ5ID0gYygiY2hyIiwgImxlbmd0aCIpKQoKIyBDcmVhdGUgcmVjb2RlIHZlY3RvcgpyZWNvZGVfdmVjID0gYygiTm9uLW1pc3NpbmcsIGJpYWxsZWxpYyBTTlBzIHBlciBtZWdhYmFzZSIsCiAgICAgICAgICAgICAgICJQcm9wb3J0aW9uIG9mIGNocm9tb3NvbWUgY292ZXJlZCBieSBleG9ucyIpCm5hbWVzKHJlY29kZV92ZWMpID0gYygic25wc19wZXJfbWVnYWJhc2UiLAogICAgICAgICAgICAgICAgICAgICAgInByb3BfY292X2V4b24iKQpgYGAKCiMjIFBsb3QKYGBge3IsIGZpZy5zaG93PSJob2xkIiwgb3V0LndpZHRoPSc1MCUnLCBmaWcuY2FwID0gIlNOUHMgcGVyIE1iIHZzIHByb3BvcnRpb24gb2YgY2hyIGNvdmVyZWQgYnkgZXhvbnMifQpjaHJfZGYgJT4lIAogIHRpZHlyOjpwaXZvdF9sb25nZXIoY29scyA9IGMoc25wc19wZXJfbWVnYWJhc2UsIHByb3BfY292X2V4b24pLCAKICAgICAgICAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInZhcmlhYmxlIiwKICAgICAgICAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJ2YWx1ZXMiKSAlPiUgCiAgZHBseXI6Om11dGF0ZSh2YXJpYWJsZSA9IGRwbHlyOjpyZWNvZGUodmFyaWFibGUsICEhIXJlY29kZV92ZWMpKSAlPiUgCiAgZ2dwbG90KCkgKwogICAgZ2VvbV9jb2woYWVzKGNociwgdmFsdWVzLCBmaWxsID0gY2hyKSkgKwogICAgZ3VpZGVzKGZpbGwgPSBGKSArIAogICAgeGxhYigiQ2hyb21vc29tZSIpICsKICAgIHlsYWIoTlVMTCkgKwogICAgdGhlbWVfYncoKSArCiAgICBmYWNldF93cmFwKH52YXJpYWJsZSwKICAgICAgICAgICAgICAgbnJvdyA9IDIsIG5jb2wgPSAxLAogICAgICAgICAgICAgICBzY2FsZXMgPSAiZnJlZV95IikKY2hyX2RmICU+JSAKICBnZ3Bsb3QoYWVzKHNucHNfcGVyX21lZ2FiYXNlLCBwcm9wX2Nvdl9leG9uLCBjb2xvdXIgPSBjaHIsIGxhYmVsID0gY2hyKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV90ZXh0KGhqdXN0ID0gLTAuNSkgKwogIHRoZW1lX2J3KCkgKwogIGd1aWRlcyhjb2xvdXIgPSBGKSArCiAgeGxhYigiTm9uLW1pc3NpbmcsIGJpYWxsZWxpYyBTTlBzIHBlciBtZWdhYmFzZSIpICsKICB5bGFiKCJQcm9wb3J0aW9uIG9mIGNocm9tb3NvbWUgY292ZXJlZCBieSBleG9ucyIpCmBgYAoKYGBge3IsIGV2YWwgPSBGfQojIFNhdmUgdG8gcmVwbwpnZ3NhdmUoZmlsZW5hbWUgPSBwYXN0ZSgiMjAyMDExMDZfc25wcy1wZXItbWJfdl9leG9uLXByb3BzIiwgIi5wbmciLCBzZXAgPSAiIiksCiAgICAgICBkZXZpY2UgPSAicG5nIiwKICAgICAgIHBhdGggPSBoZXJlKCJtaWtrX2dlbm9tZSIsICJwbG90cyIpLAogICAgICAgd2lkdGggPSAyNCwKICAgICAgIGhlaWdodCA9IDIwLAogICAgICAgdW5pdHMgPSAiY20iLAogICAgICAgZHBpID0gNTAwKQpgYGAKCiMjIENhbGN1bGF0ZSBjb3JyZWxhdGlvbgpgYGB7cn0KY29yLnRlc3QoY2hyX2RmJHNucHNfcGVyX21lZ2FiYXNlLCBjaHJfZGYkcHJvcF9jb3ZfZXhvbiwgbWV0aG9kID0gInNwZWFybWFuIikKYGBgCg==